AWS Tools for PowerShell でRun Commandを実行してみた

AWS

はじめに

好物はインフラとフロントエンドのかじわらゆたかです。

EC2 System ManagerのRun Commandは非常に便利です。これを用いることで、コマンドの実行をSSHでEC2に入ると言ったことを行わずに実行することが可能です、

定期的なバッチ処理を実行する時に基本はCronで設定するとは思いますが、何か障害等でバッチを再実行したいといったケースがあるとします。
この場合、SSHでEC2インスタンスに入って実行といった方法が一番取られやすいと思います。
ですが、例えば外出先でバッチを再実行したいといった場合、セキュリティグループの設定によってSSH経由ではEC2に入れないと言ったケースは容易に想像できます。
そういった際に、Run Commandから実行することでセキュリティグループの設定を変更をすることなくバッチの再実行を行うことが可能となります。

上記のケースに該当するのはSSHでログインするのに敷居の高いWindowsユーザーの方を想定し、Windows環境(PowerShell)で実行してみました。

下準備編

以前、AWS Tools for PowerShellでAssumeRoleによるクレデンシャル取得で取得を行いましたが、これらを他の関数からも呼び出しやすいように手を入れてみました。

{
    "Profile":"default",
    "Region":"ap-northeast-1",
    "UseRole":true,
    "RoleARN":"arn:aws:iam::1234567890:role/assume_role",
    "SerialNumber":"arn:aws:iam::1234567890:mfa/mfa"
}
function Get-AWSCredential-withMFA () {
    $settingFilepath = Join-Path  $PSScriptRoot setting.json
    $setting = Get-Content $settingFilepath -Encoding UTF8 -Raw | ConvertFrom-Json
    Initialize-AWSDefaults -Region $setting.region -ProfileName $setting.Profile 
    $credential = Get-AWSCredentials
    if ($setting.UseRole) {
        $token = Read-Host "MFA"
        $role = Use-STSRole -RoleSessionName "SIMS-Role" -RoleArn $setting.RoleARN -SerialNumber $setting.SerialNumber -TokenCode $token -Credential $credential
        $credential = $role.Credentials
    }
    return $credential
}

setting.jsonのprofileに付いては、aws cli等が参照する~/.aws/credentialの設定をしているprofileを指定します。
regionについては、実行するregionを記載します。
aws cliで用いる ~/.aws/configを模した形になっています。
useRoleをtrueとした場合、RoleArn SerialNumberを用いることになります。
これらで設定する値も~/.aws/configで設定する際と同じ値になります。

AWS CLIがAssumeRoleによる自動クレデンシャル取得とMFAに対応しました!

上記スクリプトを動かしてみたいと思います。

$ ls
Get-AWSCredential-withMFA.ps1 setting.json
$ powershell
PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.


PS /Users/kajiwarayutaka/runcommand> . ./Get-AWSCredential-withMFA.ps1
PS /Users/kajiwarayutaka/runcommand> Get-AWSCredential-withMFA
MFA: 123456

AccessKeyId          Expiration          SecretAccessKey                          SessionToken
-----------          ----------          ---------------                          ------------
AKIAZZZZZZZZZZZZZZZZ 2017/04/11 21:24:57 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz sssssssssssssssssss...

このような形でMFAを用いたAssumeRoleによる自動クレデンシャル取得できたことがわかります。

Run Commandを実行してみる

上記のPowerShellも取り込んだ形で、RunCommandを動かしてみたいと思います。

. $PSScriptRoot\Get-AWSCredential-withMFA.ps1
$credential = Get-AWSCredential-withMFA
Set-AWSCredentials -Credential $credential
$instanceID = "i-12345678901234567"
$parameter = @{commands="ifconfig"}
$commandResponse =  Send-SSMCommand -Comment "ipconfig" -DocumentName "AWS-RunShellScript" -instanceId $instanceID -Parameter $parameter
while ($commandResponse.Status -eq "Pending") {
    Start-Sleep -m 1000
    $commandResponse = Get-SSMCommand  -CommandId $commandResponse.CommandId
}
$result = Get-SSMCommandInvocation -InstanceId $instanceID -CommandId $commandResponse.CommandId -Detail $TRUE
foreach ($OutptResult in $result.CommandPlugins) {
    Write-Host $OutptResult.Output
}

上記のコードは以下の様な処理で動いています。

  1. 1〜3行目で下準備で作成したMFAを用いたAssumeRoleにてCredentialの取得を行なっています。
  2. 次に、4行目でRun Commandを実行させるインスタンスのIDを指定しています。
  3. 5行目では動かすコマンドを指定しています。ここではifconfigを実行しています。
  4. 6行目でSystemSendManagerに対して対象のインスタンスにコマンドを実行するように指定しています。
  5. 7〜10行目でResponseがpendingから変わるまでループで待ちます
  6. 11行目でRun Commandの結果を取得し、12〜14行目で結果を表示しています。

実際に実行すると以下の様な形になります。

PS> .run-command.ps1
MFA: 123456
eth0      Link encap:Ethernet  HWaddr 06:04:22:85:37:91
          inet addr:172.31.24.225  Bcast:172.31.31.255  Mask:255.255.240.0
          inet6 addr: fe80::404:22ff:fe85:3791/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:6253 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3530 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:7625904 (7.2 MiB)  TX bytes:297254 (290.2 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:140 (140.0 b)  TX bytes:140 (140.0 b)

Mac環境でのPowershell & AWS Tools for PowerShell Core Editionの導入

また、コチラのPowershellはMacやLinux環境でも導入できるPowerShellでも動くことを確認しています。

homebrew経由でのPowershellは以下の様な感じでインストールできました。

$ brew cask install powershell
==> Migrating Caskroom from /opt/homebrew-cask/Caskroom to /usr/local/Caskroom.
==> Creating symlink from /usr/local/Caskroom to /opt/homebrew-cask/Caskroom.
==> Caveats
A OpenSSL-backed libcurl is required for custom handling of certificates.
This is rarely needed, but you can install it with
  brew install curl --with-openssl
See https://github.com/PowerShell/PowerShell/issues/2211

==> Satisfying dependencies
==> Installing Formula dependencies from Homebrew
openssl ... already installed
complete
==> Downloading https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.17/powershell-6.0.0-alpha.17.pkg
######################################################################## 100.0%
==> Verifying checksum for Cask powershell
==> Running installer for powershell; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are ignored.
Password:
==> installer: Package name is powershell-6.0.0-alpha.17
==> installer: Installing at base path /
==> installer: The install was successful.
🍺  powershell was successfully installed!

AWS Tools for PowerShell Core Editionの導入については、
管理者権限でpowershellを立ち上げた後以下のコマンドでインストール可能です。

PS>  Install-Module -Name AWSPowerShell.NetCore

最後に

Run Commandをシェルで動かす方法は、ブログでも各種紹介されておりましたが、
PowerShell環境でWindowsやMacでも動かすことができました。

上記を用いることでインスタンスの管理をSSHで接続することなく、
Windows環境からでも管理等できそうです。