0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【AWS】プロキシ設定が原因でSSM Automationが失敗した場合の対処法

Last updated at Posted at 2022-10-03

はじめに

※かなり長い記事になるので、プロキシサーバはすでに作成済み、原因のとこだけ知りたいって方は12項のAutomationの実行に失敗した原因から先を読んでいただければと思います。

SSMオートメーションを実行すれば勝手にZIPをダウンロードしてきてEC2内のドライバが自動アップデートされるような仕組みって便利ですよね。
今回はそんな仕組みを作ろうとしたはいいが、プロキシの壁に阻まれ苦悩した結果を記事にまとめてみました。
セキュリティが厳しい会社様など、プロキシサーバが原因で処理が止まってしまった・詰まってしまった。。。ってときの解決法の1つになれば幸いです。
※本記事ではVPC内のEC2からS3への接続を行うので、VPCエンドポイントを使うのがベストプラクティスではありますが、あえてインターネット経由で取得するようにしてます。

目次

  1. プロキシサーバとは
  2. 概要図
  3. VPCを作成する
  4. EC2を起動する
  5. プロキシサーバを作成する
  6. セッションマネージャ接続がうまくいかない場合
  7. セキュリティグループを作成する
  8. SystemsManagerで疎通状況を確認する
  9. プロキシの設定を行う
  10. SystemsManagerで疎通状況を再度確認する
  11. Automationを実行する
  12. Automationの実行に失敗した原因
  13. LOCALSYSTEMのプロキシ設定を確認
  14. LOCALSYSTEMのプロキシ設定を変更
  15. Automatioを再実行する
  16. さいごに

プロキシサーバとは

まずはじめにプロキシサーバってなに?
よく聞くけどどんなことするのかよくわかってない...という方向けに簡単に説明します。
プロキシサーバとはインターネットに接続されていないサブネット内(プライベートサブネット)のサーバが、インターネットに接続する際に中継するために使用するサーバです。もう少しかみ砕くとプライベートサブネット内サーバの代わりにインターネットに向けてリクエストを送信してくれるサーバのことです。
詳しい話は割愛させていただきますが、プロキシサーバを使用することで怪しいサイトや許可していないドメインへのアクセスをブロックできるなど、セキュリティ面でのメリットもあります。

概要図

本記事では概要図のようなイメージで構築を行います。
パブリックサブネットにプロキシサーバ(Linux)、プライベートサブネットにWindowsServerを1台ずつ構築し、WindowsServerに対してSSMAutomationを実行します。
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
踏み台サーバはプライベートサブネットのEC2にRDPで接続し、プロキシの設定を行うために使用してますが、フリートマネージャを使用してもOKです!!
image.png
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

Automation用ドキュメントには「AWSSupport-UpgradeWindowsAWSDrivers」を使用して、インターネットからzipファイルを取得できるか検証します。
※プロキシの設定がうまくできていないと、インターネットからファイルをダウンロードできず失敗します。
image.png

VPCを作成する

画像のような感じでサブネットを2つ(パブリックサブネットとプライベートサブネット)作ってください。
Cidrは自由に変更してください
image.png

image.png

EC2を起動する

パブリックサブネットとプライベートサブネットにEC2を起動します。
プロキシサーバはパブリックサブネットに作成し、パブリックIPアドレスを設定してください。
image.png
image.png
image.png

プロキシサーバを作成する

起動したLinuxサーバ(qiita-proxy)にセッションマネージャで接続します。
接続できたら以下のコマンドを実行し、squidをインストールします。
うまく接続できない場合はこちらを参考にしてください。

  1. セッションマネージャ接続がうまくいかない場合
#squidをインストールする
yum install squid

image.png
設定ファイルの格納場所:「/etc/squid」
設定ファイル名:squid.conf
image.png

「squid.conf」の中身はデフォルトだとこんな感じになってます。
今回はこのまま変更しないで使用します。
image.png

  • ポートを確認する
    以下のコマンドでsquidがport:3128を使用していることを確認します。(プロキシ設定時にポートの指定で必要です)
lsof -i:3128

image.png

セッションマネージャ接続がうまくいかない場合

パブリックサブネットのルートテーブルにIGWへのルートが存在する場合、EC2のロールにセッションマネージャ接続で必要な権限が不足している可能性があります。
その場合はEC2のロールに以下のポリシーを付与されているか確認してください。

  • 必要な権限:AmazonSSMManagedInstanceCore

過去にセッションマネージャを使用したCloudFormationに関する記事も書いているのでよかったら参考にしてみてください。

セキュリティグループを作成する

セキュリティグループを3つ作成します。
1つ目はプロキシサーバ(Linux)用、2つ目はプライベートサブネットに作成するEC2(windows Server)用,3つ目は踏み台サーバ用です。
セキュリティ面を考慮するともっとガチガチのルールにしたほうがいいですが、
今回は検証なのでそれぞれのサーバのSGからの通信はすべて許可といった感じにしてます。
作成したらそれぞれのEC2にアタッチします。

  • 踏み台サーバ用
    踏み台サーバにRDPするIPをインバウンドルールに追加してください。
    image.png
    image.png

  • プロキシサーバ用
    image.png
    image.png

  • プライベートサブネットEC2(WindowsServer)用
    image.png

SystemsManagerで疎通状況を確認する

SystemsManagerでAutomationを実行するためにはインスタンスにSSMAgentがインストールされており、マネージドインスタンスとして認識されている必要があります。
プロキシ設定前の状態を確認してみます。

SystemsManagerのフリートマネージャを開きます。
まだプロキシの設定を行っていないのでプライベートサブネット内のEC2(proxy-access-test)がマネージドノードとして認識されていません。
image.png

プロキシの設定を行う

踏み台サーバ経由でプライベートサブネットのWindowsServer(proxy-access-test)にRDP接続します。
※RDPがうまくいかない場合は接続先EC2のSGのインバウンドで許可されているか、接続元のEC2のSGのアウトバウンドが許可されているか確認してみてください。
image.png

プライベートサブネット内のEC2に対してプロキシの設定を行います。
プロキシの設定を行うことでパブリックサブネットに作成したプロキシサーバを経由して
EC2内のSSMAgentがインターネットに接続できるようになり、SystemsManagerでもマネージドフリートとして認識されるようになります。

SSMAgentがインターネットに接続するために使用されるプロキシ設定にはいくつか種類があり、優先度があります。
今回は1番優先度の高いAmazonSSMAgentレジストリ設定を使用します。

プロキシ設定の優先順位について、詳しくはこちらのドキュメントをご覧ください。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-install-ssm-proxy.html

【プロキシの優先度】
1.AmazonSSMAGent レジストリ設定 (HKLM:\SYSTEM\CurrentControlSet\Services\AmazonSSMAgent)
2.システム環境変数 (http_proxy、https_proxy、no_proxy)
3.LocalSystem ユーザーアカウントの環境変数 (http_proxy、https_proxy、no_proxy)
4.Internet Explorer の設定 (HTTP、セキュア、例外)
5.WinHTTP プロキシ設定 (http=、https=、bypass-list=)
  • PowerShellを開き以下のコマンドを実行します
    3行目の「hostname:port」は プロキシサーバのプライベートIPアドレス、プロキシサーバを作成するで確認したport番号 に書き換えて実行してください。
$serviceKey = "HKLM:\SYSTEM\CurrentControlSet\Services\AmazonSSMAgent"
$keyInfo = (Get-Item -Path $serviceKey).GetValue("Environment")
$proxyVariables = @("http_proxy=hostname:port", "https_proxy=hostname:port", "no_proxy=169.254.169.254")

if ($keyInfo -eq $null) {
    New-ItemProperty -Path $serviceKey -Name Environment -Value $proxyVariables -PropertyType MultiString -Force
} 
else {
    Set-ItemProperty -Path $serviceKey -Name Environment -Value $proxyVariables
}
Restart-Service AmazonSSMAgent
  • 以下のコマンドをPowerShellで実行し、SSMAgentのレジストリ設定を確認します。
    Environmentの行が追加されていればOKです。
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\AmazonSSMAgent"

image.png

SystemsManagerで疎通状況を再度確認する

SSMAgentレジストリ設定を行うことでプロキシを経由してSSMAgentがインターネットと通信できるようになりました。
先ほど同様にSystemsManagerのフリートマネージャで疎通状況を確認してみます。
今度はプライベートサブネットに作成したEC2(proxy-access-test)が認識されました!
image.png

Automationを実行する

SSMドキュメント「AWSSupport-UpgradeWindowsAWSDrivers」を実行してみます。
SystemsManagerの「ドキュメント」を開き、「Amazonが所有」を選んだ状態で「AWSSupport-UpgradeWindowsAWSDrivers」と検索します。
image.png
ドキュメント名を選択し、右上の「オートメーションを実行する」を押下します
image.png
「シンプルな実行」を選び、プライベートサブネットに作成したインスタンス(proxy-access-test)を選択します。
そのままが右下の「実行」を押下します
image.png

オートメーションが開始されます
image.png
実行結果
image.png

プロキシの設定をし、マネージドフリートとして認識されているのに失敗してしまいました。

具体的にどんな処理を行っているのかドキュメント内を確認してみます。
※長いので最初に失敗したインストール処理(installAwsEnaNetworkDriverOnInstance)だけ載せます

      "name": "installAwsEnaNetworkDriverOnInstance",
      "action": "aws:runCommand",
      "onFailure": "Continue",
      "inputs": {
        "DocumentName": "AWS-RunPowerShellScript",
        "InstanceIds": [
          "{{ InstanceId }}"
        ],
        "Parameters": {
          "commands": [
            "try {",
            "    if (Test-Path -Path \"ena-state-{{ automation:EXECUTION_ID }}\") {",
            "        if (Select-String -Path \"ena-state-{{ automation:EXECUTION_ID }}\" -Pattern \"success\") {",
            "            Write-Host \"Installer has already run. Skipping installation\"",
            "            exit 0",
            "        }",
            "        else {",
            "            Write-Host \"Previous run of installer marked as failure. Skipping installation\"",
            "            exit 1",
            "        }",
            "    }",
            "    else {",
            "        # Download drivers",
            "        $url = \"https://s3.amazonaws.com/ec2-windows-drivers-downloads/ENA/Latest/AwsEnaNetworkDriver.zip\"",
            "        $tempPath = (Resolve-Path ${env:temp}).Path",
            "        Write-Host \"Downloading AWS ENA drivers\"",
            "        $tempFile = \"${tempPath}\\AwsEnaNetworkDriver.zip\"",
            "        $tempDir = \"${tempPath}\\AwsEnaNetworkDriver\"",
            "        $wc = New-Object \"System.Net.WebClient\"",
            "        $wc.Headers.Add(\"user-agent\", \"AWSSupport-UpgradeWindowsAWSDrivers\")",
            "        $wc.DownloadFile($url, $tempFile)",
            "        if (Test-Path $tempDir) {",
            "            Remove-Item -Path $tempDir -Recurse -Force",
            "        }",
            "",
            "        # Extract drivers",
            "        try {",
            "            # Unpacking the file this way is not supported in PowerShell 2",
            "            Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue",
            "            [System.IO.Compression.ZipFile]::ExtractToDirectory($tempFile, $tempDir)",
            "        }",
            "        catch [System.InvalidOperationException] {",
            "            # Legacy unpacking method using COM Object",
            "            # Works with PowerShell 2",
            "            New-Item -Path $tempDir -ItemType \"directory\" -Force | Out-Null",
            "            ((New-Object -com shell.application).NameSpace($tempDir)).CopyHere(((New-Object -com shell.application).NameSpace($tempFile)).Items())",
            "        }",
            "",
            "        # Run install.ps1",
            "        Write-Host \"Running install script\"",
            "        $output = & \"${tempDir}\\install.ps1\" -NoReboot",
            "        Write-Host $output",
            "",
            "        # Evaluate output",
            "        New-Item \"ena-state-{{ automation:EXECUTION_ID }}\" -ItemType file | Out-Null",
            "        if ($output -match \"successful\") {",
            "            if ($output -match \"reboot\") {",
            "                Write-Host \"Rebooting to complete installation\"",
            "                Write-Output \"success\" | Set-Content -Path \"ena-state-{{ automation:EXECUTION_ID }}\"",
            "                exit 3010",
            "            }",
            "            Write-Output \"success\" | Set-Content -Path \"ena-state-{{ automation:EXECUTION_ID }}\"",
            "            exit 0",
            "        }",
            "        else {",
            "            Write-Output \"failure\" | Set-Content -Path \"ena-state-{{ automation:EXECUTION_ID }}\"",
            "            exit 1",
            "        }",
            "    }",
            "}",
            "catch {",
            "    Write-Host $_.Exception.Message",
            "    exit 255",
            "}"
          ]
        }
      },
      "isCritical": "true",
      "nextStep": "installAWSNVMeOnInstance"
    },

処理内容を簡単に解説すると、PowerShellでコマンドを実行し、
「 $url = "https://s3.amazonaws.com/ec2-windows-drivers-downloads/ENA/Latest/AwsEnaNetworkDriver.zip」
で指定したURLからzipファイルをダウンロードしてきています。

エラーメッセージを見てみしょう。
どうやらリモートサーバに接続できていないっぽいですね。
この場合は指定したURLにアクセスできなかったということを表しています。

image.png

【エラーメッセージを抜粋】
Downloading AWS ENA drivers
Exception calling "DownloadFile" with "2" argument(s): "Unable to connect to the remote server"

Automationの実行に失敗した原因

SSMAgentレジストリの設定を行ってマネージドフリートとして認識されているにも拘わらず、なぜ失敗したのでしょうか。
原因はオートメーションを実行する際に使用されるユーザのプロキシ設定に問題があります。

SSMオートメーション(runCommand)実行時にはサービスアカウントの「LOCALSYSTEM」が使用されます。
また、プロキシ設定は「LOCALSYSTEM」のInternetExplorer(インターネットオプション)のプロキシ設定が使用されます。
インターネットオプションのプロキシ設定はユーザ単位で行う必要があるため、「LOCALSYSTEM」のプロキシ設定が施されていない状態でrunCommandを実行しても、プロキシサーバにたどり着けず処理に失敗してしまうというわけです。

LOCALSYSTEMのプロキシ設定を確認

今回はコマンドベースで行います。

#PowerShellで実行
bitsadmin /util /getieproxy LOCALSYSTEM

image.png

確認の結果、「Proxy usage: AUTODETECT」となっていることが分かりました。
各種パラメータについてはMicrosoft公式ドキュメントをご確認ください。
https://learn.microsoft.com/ja-jp/windows-server/administration/windows-commands/bitsadmin-util-and-setieproxy

#コマンドプロンプトで以下のコマンドを実行
PsExec.exe -i -s powershell.exe

#PowerShellが開くのでコマンドを実行
inetcpl.cpl

LOCALSYSTEMのプロキシ設定を変更

プロキシの設定変更を行います。
こちらも確認同様コマンドベースで実行します。
ポート番号についてはプロキシサーバを作成するで確認したポートを指定してください。

#PowerShellで実行
bitsadmin /util /setieproxy LOCALSYSTEM MANUAL_PROXY プロキシサーバのプライベートIP:ポート "169.254.169.254;"
bitsadmin /util /getieproxy LOCALSYSTEM

image.png

Proxy listとProxy bypassが設定されたことが確認できました。

Automationを再実行する

同じドキュメントを実行してみます。
LOCALSYSTEMのプロキシ設定を行っているので、今度は成功するはずです。
image.png

無事に成功しました!!

さいごに

プロキシサーバの構築をやったことがなかったので、いまいち仕組みを理解していなかったところがあったのですが、今回のトラブル対応でかなり勉強になりました。
プロキシを使っている人で同様のトラブルに見舞われる方がいるかもしれないので、この記事がどこかの誰かの参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?