(小ネタ)Packerを用いてAssumeRoleのAWSアカウントにカスタムAMIを作成する方法

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、コカコーラが大好きなカジです。

Packerを用いてAssumeRoleのAWSアカウントにカスタムAMIを作成する方法を知らなかったので、メモとして書きます。

手順

Packerは以下のバージョンで確認しました。

% packer --version
0.10.1

STSで、一時トークンと一時クレデンシャルを発行

まず、AWS CLI でSecurity Token Service (STS) で一時トークンと一時クレデンシャルを発行します。

STSのコマンド詳細はクロスアカウントなAWS CLI処理でハマった話参照

$ aws sts assume-role --role-arn arn:aws:iam::foo:role/role-kawahara --role-session-name tektito_na_namae --serial-number arn:aws:iam::hoge:mfa/user-kawahara --token-code 123456(←ここはMFAコードの6桁の数列)
{
    "AssumedRoleUser": {
        "AssumedRoleId": "AROAIS2TA7QMDOV77CXMU:tektito_na_namae",
        "Arn": "arn:aws:sts::foo:assumed-role/role-kawahara/tektito_na_namae"
    },
    "Credentials": {
        "SecretAccessKey": "XXXXXXXXXXXXXXXXXXX",
        "SessionToken": "YYYYYYYYYYYYYYYYYYYYY",
        "Expiration": "2015-08-12T15:58:18Z",
        "AccessKeyId": "ZZZZZZZZZZZZZZZZZZZZZZZZ"
    }
}

Packerテンプレートへ上記の結果を埋め込み

上記で取得したものを、packerのファイルに埋め込むことで可能です。 (わかると簡単なのですが、「USER VARIABLES」をきちんと理解しておらず、記述間違いでハマりました。望月先輩に助けてもらいました。この場を借りてお礼。)

Packer の テンプレート例

{
  "variables": {
        "aws_access_key":     "<AccessKeyId>",
        "aws_secret_key":     "<SecretAccessKey>",
        "aws_security_token": "<SessionToken>"
  },
  "builders": [
    {
      "type": "amazon-ebs",
      "access_key":               "{{user `aws_access_key`}}",
      "secret_key":               "{{user `aws_secret_key`}}",
      "token":                    "{{user `aws_security_token`}}",
      "region": "ap-northeast-1",
      "source_ami": "ami-29160d47",
      "instance_type": "t2.micro",
      "ssh_username": "ec2-user",
      "ssh_timeout": "10m",
      "ami_name": "Proto Type EC2 {{timestamp}}"
    }
  ],

  "provisioners": [
    {
    "type": "shell",
    "script": "hogehoge_install.sh"
    }
  ]
}

環境変数から取得する場合は、variablesの部分を以下に変更

    "variables": {
        "aws_access_key":     "{{env `AWS_ACCESS_KEY_ID`}}",
        "aws_secret_key":     "{{env `AWS_SECRET_ACCESS_KEY`}}",
        "aws_security_token": "{{env `AWS_SECURITY_TOKEN`}}"
    },

汎用性を上げるために

ただし、STSが一時的なものなので上記のように埋め込まずに、variablesファイルとしてPackerを実行した方が、Packerのテンプレートの利便性が高いことを知りました。 STSの出力結果から、Packerで利用するvariables.jsonを出力する簡単なスクリプトを作成しました。

variables.jsonを出力スクリプト

単純に必要なところを抜き出して、置き換えているだけです。すみません。

$ cat var-file-export.sh
#!/bin/sh
FILE=$1

echo "{"
 cat $FILE | egrep 'AccessKeyId|SecretAccessKey|SessionToken' |
  sed 's/AccessKeyId/aws_access_key/g' |
  sed 's/SecretAccessKey/aws_secret_key/g' |
  sed 's/SessionToken/aws_security_token/g'
echo "}"

STSの結果をファイルに出力(sts-result.txt)しておいて以下でvariables.jsonに変換

$ ./var-file-export.sh sts-result.txt > variables.json
$ cat variables.json
{
        "aws_secret_key": "XXXXXXXXXXXXXXXXXXX",
        "aws_security_token": "YYYYYYYYYYYYYYYYYYYYY",
        "aws_access_key": "ZZZZZZZZZZZZZZZZZZZZZZZZ"
}

AMI作成時のコマンド

$ packer build -var-file=variables.json template.json

上記のPackerテンプレートファイル(template.json)にはvariablesを別に読み込むので不要です。 Packerテンプレートファイルが流用しやすくなりましたね。

$ cat template.json
{
  "builders": [
    {
      "type": "amazon-ebs",
      "access_key":               "{{user `aws_access_key`}}",
      "secret_key":               "{{user `aws_secret_key`}}",
      "token":                    "{{user `aws_security_token`}}",
      "region": "ap-northeast-1",
      "source_ami": "ami-29160d47",
      "instance_type": "t2.micro",
      "ssh_username": "ec2-user",
      "ssh_timeout": "10m",
      "ami_name": "Proto Type EC2 {{timestamp}}"
    }
  ],

  "provisioners": [
    {
    "type": "shell",
    "script": "hogehoge_install.sh"
    }
  ]
}

どなたかのお役に立てれば幸いです。

参考元

クロスアカウントなAWS CLI処理でハマった話

https://github.com/mitchellh/packer/issues/3070

https://groups.google.com/forum/#!topic/packer-tool/AXXCg_MFpuw