ようへいの日々精進XP

よかろうもん

2017 年 07 月 08 日(土)

ジョギング

  • 香椎浜 x 2.5 周
  • 11 時過ぎからスタートしたのが間違っていた(暑さでフラフラ

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

仕事でやらかした

  • 当たり前にやっておくべきことが漏れててやらかしてしまった
  • 当たり前のことが出来ていなかったのがとても悔しい

俺のチュートリアル 2017 夏 〜 チュートリアルで学ぶ IAM Role によるクロスアカウントアクセス 〜

はじめに

以下のチュートリアルを参考にしつつ、シンプルな構成を使って AWS のクロスアカウントアクセスを試してみたメモ。

docs.aws.amazon.com

構成

下図のような構成を想定。

f:id:inokara:20170708105112p:plain

やりたいことをスーパーシンプル三行で説明すると…

  • Account xxxx-xxxx-0001 の適切に管理されている S3 バケットに
  • Account xxxx-xxxx-0002 の適切な IAM Role が付与されている EC2 から
  • 出来るだけ安全にアクセスしたい(とりあえず閲覧出来れば OK)

チュートリアル

Account xxxx-xxxx-0001 の設定

IAM Role

以下の Trust relationships を適用して IAM Role の role-01 を作成する。

$ cat role-01.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::xxxxxxxx0002:role/role-02"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

$ aws \
  --profile ${Account xxxx-xxxx-0001 の PROFILE} \
    iam create-role \
      --role-name role-01 \
      --assume-role-policy-document file://role-01.json \
      --query Role.Arn \
      --output text

IAM Role に付与するポリシー

role-01 に付与するポリシーは、以下のように S3 バケットのオブジェクトを取得できるだけのポリシー AmazonS3ReadOnlyAccess を付与する。

$ cat policy-01.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Resource": "*"
    }
  ]
}

$ aws \
  --profile ${Account xxxx-xxxx-0001 の PROFILE} \
    iam put-role-policy \
      --role-name role-01 \
      --policy-name policy-01 \
      --policy-document file://policy-01.json

ここはアクセスさせたい対象に応じて設定すれば良いと思う。

Account xxxx-xxxx-0002 の設定

IAM Role

以下の Trust relationships を適用して IAM Role の role-02 を作成する。

$ cat role-02.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

$ aws \
  --profile ${Account xxxx-xxxx-0002 の PROFILE} \
    iam create-role \
      --role-name role-02 \
      --assume-role-policy-document file://role-02.json \
      --query Role.Arn \
      --output text

IAM Role に付与するポリシー

arn:aws:iam::xxxxxxxx0001:role/role-01 に対して AssumeRole 出来るポリシーを付与する。

$ cat policy-02.json
{
    "Version": "2012-10-17",
    "Statement": [
       {
           "Effect": "Allow",
           "Action": "sts:AssumeRole",
           "Resource": "arn:aws:iam::xxxxxxxx0001:role/role-01"
       }
    ]
}

$ aws \
  --profile ${Account xxxx-xxxx-0002 の PROFILE} \
    iam put-role-policy \
      --role-name role-02 \
      --policy-name policy-02 \
      --policy-document file://policy-02.json

Instance Profile

$ aws \
  --profile cloudpack-kappa \
      iam create-instance-profile \
        --instance-profile-name role-02

$ aws \
  --profile cloudpack-kappa \
      iam add-role-to-instance-profile \
        --instance-profile-name role-02 \
        --role-name role-02

最終的にこんな感じ?

こんな感じで図に書くとわかり易い。個人的に。

f:id:inokara:20170708102819p:plain

動作確認

STS に AssumeRole して一時的に認証情報を取得するスクリプト

Account xxxx-xxxx-0002 の EC2 から Account xxxx-xxxx-0001 の S3 バケットにアクセスする為には STSAWS Security Token Service) に AssumeRole して一時的に認証情報を取得する必要があるので、以下のような AWS SDK for Go を利用したツールを使って認証情報を取得するツールを噛まして S3 バケットにアクセスしてみる。

gist.github.com

Account xxxx-xxxx-0002 の EC2 で以下のように実行する。

./oreno-assume -role_arn arn:aws:iam::xxxxxxxx0001:role/role-01 -command "aws s3 ls s3://foobar/"

Access Denied

oreno-assume を利用していない場合には、以下のように Access Denied となる。

$ aws s3 ls s3://foobar/

An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied

アクセス OK

Assume Role してからアクセスすると…以下のようにアクセス出来る。

./oreno-assume -role_arn arn:aws:iam::xxxxxxxx0001:role/role-01 -command "aws s3 ls s3://foobar/"
                           PRE logs/
2014-07-01 01:29:52          0 404.html
2014-12-05 01:14:23         37 Hello.txt
2014-12-04 23:52:22         87 hello.html
2014-07-01 01:29:52          0 index.html

終わり

クロスアカウントアクセスのポイント

  • 信頼する AWS アカウント又は IAM Role 及び IAM User をプリンシパルした IAM Role を作る(チュートリアル中の role-01 を指す)
  • ↑で作成した IAM Role にアクセスさせたいリソースへのポリシーを付与する(チュートリアル中の policy-01 を指す)
  • 信頼されている AWS アカウント又は IAM Role(チュートリアル中の role-02 のこと)には role-01 に対する Assume Role 権限が付与されたポリシーをアタッチする(チュートリアル中の policy-02 を指す)

ちゃんと用語を理解しきれていないので誤りがあるかもしれないが…思ったりよりも簡単だった。

参考

docs.aws.amazon.com

blog.serverworks.co.jp

そして、俺の夏が

はじまる。

2017 年 07 月 07 日(金)

七夕

なのに今日も引き続き大雨。

ジョギング

  • 香椎浜 x 2 周
  • 晴れ間にスタートしたけど、帰りはシトシト雨に降られた

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

終日

ベランダの風の抜け方が気持ち良かったので終日ベランダで作業。

ベランダがオフィス。

この写真を遺影にしたいと思う。

2017 年 07 月 06 日(木)

大雨

  • すごいことになっている
  • 亡くなった方もいらっしゃるようで、被災された方々には心からお見舞い申し上げます

ジョギング

  • 雨の為無し

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

奥さん

最後の有給を使って体を休ませることに。義父が亡くなってからずっと気持ちが張り詰めていたし、最近の暑さなどが追い打ちになってしまったのだろう。

とりあえず、今日はゆっくり休んでもらって、明日は元気に仕事に行けるといいな。

2017 年 07 月 05 日(水)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

奥さん

仕事から帰ってくるなり体がだるいと言って寝込む。暑さの影響かな…心配。

ひとまず、特製ビビンバ丼(肉なし)を作って少しだけ食べさせる。

2017 年 07 月 04 日(火)

タイフーン

朝からタイフーンの影響による雨だったのでジョギングはお休み。足も痛いし。

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

夕飯

パスタを作る。パスタの茹で加減が絶妙だったと思う(過去に作ったパスタ比)

2017 年 07 月 03 日(月)

ジョギング

  • 香椎浜 x 2 周
  • 誰に煽られた訳でもないが、これまでで最速の 29 分台で周りきった
  • やりすぎた感

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

夕飯

実家から大量にジャガイモが送られてきていたので、自分がイメージしていたアンチョビポテトを作ってみたが失敗だった。

2017 年 07 月 02 日(日)

ジョギング

  • 香椎浜 x 2.5 周
  • 暑さのせいか体の動きがイマイチ

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

俺の EC2 〜 郷編 〜

もはや Golang

インフラエンジニアを自称するものにとって心得ておかなければならないプログラム言語では?という強い危機感と、これからどうやって Golang を勉強していけばいいんだろうと不安になっていたら、お仕事等で Bash + AWS CLI でその場限りのツールをポツポツ作ったりしているので、それを Golang で作ってみることにした。

ということで、describe instances して、テーブル形式、カンマ区切り形式、Markdown 形式、dnsmasq の hosts リスト形式で出力するコマンドラインツールを Golang で作ってみた。

作ったもの

gist.github.com

使い方

準備

#
# go のバージョンを確認
#
$ go version
go version go1.8.3 darwin/amd64

#
# 必要なパッケージを取得
#
$ go get  github.com/aws/aws-sdk-go
$ go get  github.com/olekukonko/tablewriter

ビルド

$ wget --no-check-certificate https://gist.githubusercontent.com/inokappa/12b0f484bdae8876f6917ff5b43dcfae/raw/ff44c6c6c658d8cf82d6d1a71a5f22d5942f95d2/oreno-ec2.go
$ go build oreno-ec2.go

特にビルドしなくても go run でも動く。但し、結果が出力されるまで時間を要する。

help

$ ./oreno-ec2 -help
Usage of ./oreno-ec2:
  -comma
        カンマ区切りの hosts リストを生成する
  -command string
        指定したコマンドを実行する
  -dnsmasq
        dnsmasq 用の hosts リストを生成する
  -markdown
        Markdown のテーブルフォーマットで出力する
  -path string
        ファイルのパスを指定する (default "hosts_list")
  -profile string
        AWS Shared Credential の Profile 名を指定する
  -read
        -path オプションで指定したファイルを読み取る
  -region string
        AWS Region 名を指定する (default "ap-northeast-1")

ヘルプが日本語ですいません。

EC2 一覧を出力

AWS CLI--output table オプションとほぼ同じ。

$ ./oreno-ec2
+------------------+---------------------+--------------+-----------------+---------------+----------------+---------+
|     TAG:NAME     |     INSTANCEID      | INSTANCETYPE |       AZ        |   PRIVATEIP   |    PUBLICIP    | STATUS  |
+------------------+---------------------+--------------+-----------------+---------------+----------------+---------+
| dev-aaa1         | i-xxxxxxxxxxxxxxxxx | t2.micro     | ap-northeast-1a | 172.31.x.187  | Not assignment | stopped |
| dev-bbb1         | i-xxxxxxxxx         | t2.micro     | ap-northeast-1a | 172.31.x.39   | Not assignment | stopped |
| hogehoge         | i-yyyyyyyyyyyyyyyyy | t2.micro     | ap-northeast-1a | 172.31.x.89   | Not assignment | stopped |
| dev-ccc1         | i-zzzzzzzzz         | t2.medium    | ap-northeast-1a | 172.31.x.139  | Not assignment | stopped |
| dev-ddd1         | i-pppppppppp        | t2.micro     | ap-northeast-1a | 172.31.x.117  | xx.xxx.xxx.xx  | running |
| dev-eee1         | i-qqqqqqqqqqqqqq    | t2.micro     | ap-northeast-1a | 172.31.x.28   | Not assignment | stopped |
+------------------+---------------------+--------------+-----------------+---------------+----------------+---------+

出力出来る項目数だけで比較すると AWS CLI を利用した方がいいかな…

dnsmasq の hosts リストを出力

dnsmasq の --address= で指定する /Domain/IPAddress 形式のリストを -path で指定したファイルに出力する。

$ ./oreno-ec2 -dnsmasq -path dnsmasq.txt
$ ./oreno-ec2 -read -path dnsmasq.txt
address=/dev-aaa1/172.31.x.187
address=/dev-bbb1/172.31.x.39
address=/hogehoge/172.31.x.89
address=/dev-ccc1/172.31.x.139
address=/dev-ddd1/172.31.x.117
address=/dev-eee1/172.31.x.28

-read オプションはコマンドの cat と全く同じ機能。単に Golang でファイルを読み込む方法を勉強したかった為に実装した。

func read_hosts_list_file(file_path string) {
    contents, _ := ioutil.ReadFile(file_path)
    fmt.Println(string(contents))
}

ioutil.ReadFile にファイルのパスを指定するだけで読み込めるらしい。なるほど。ioutil 便利。

カンマ区切りでファイルに出力

$ ./oreno-ec2 -comma -path comma.txt
$ ./oreno-ec2 -read -path comma.txt
dev-aaa1,i-xxxxxxxxxxxxxxxxx,t2.micro,ap-northeast-1a,172.31.x.187,Not assignment,stopped
dev-bbb1,i-xxxxxxxxx,t2.micro,ap-northeast-1a,172.31.x.39,Not assignment,stopped
hogehoge,i-yyyyyyyyyyyyyyyyy,t2.micro,ap-northeast-1a,172.31.x.89,Not assignment,stopped
dev-ccc1,i-zzzzzzzzz,t2.medium,ap-northeast-1a,172.31.x.139,Not assignment,stopped
dev-ddd1,i-pppppppppp,t2.micro,ap-northeast-1a,172.31.x.117,52.198.32.108,running
dev-eee1,i-qqqqqqqqqqqqqq,t2.micro,ap-northeast-1a,172.31.x.28,Not assignment,stopped

カンマ区切り。一応、Excel でファイルを開くと CSV として解釈してくれるので有難い。

Markdown フォーマットのテーブル形式で出力

$ ./oreno-ec2 -markdown
|     TAG:NAME     |     INSTANCEID      | INSTANCETYPE |       AZ        |   PRIVATEIP   |    PUBLICIP    | STATUS  |
|------------------|---------------------|--------------|-----------------|---------------|----------------|---------|
| dev-aaa1         | i-xxxxxxxxxxxxxxxxx | t2.micro     | ap-northeast-1a | 172.31.x.187  | Not assignment | stopped |
| dev-bbb1         | i-xxxxxxxxx         | t2.micro     | ap-northeast-1a | 172.31.x.39   | Not assignment | stopped |
| hogehoge         | i-yyyyyyyyyyyyyyyyy | t2.micro     | ap-northeast-1a | 172.31.x.89   | Not assignment | stopped |
| dev-ccc1         | i-zzzzzzzzz         | t2.medium    | ap-northeast-1a | 172.31.x.139  | Not assignment | stopped |
| dev-ddd1         | i-pppppppppp        | t2.micro     | ap-northeast-1a | 172.31.x.117  | 52.198.32.108  | running |
| dev-eee1         | i-qqqqqqqqqqqqqq    | t2.micro     | ap-northeast-1a | 172.31.x.28   | Not assignment | stopped |

お仕事で Wiki 等にインスタンス一覧を資料として書くことが多々あるので便利だろうなあと思って追加した。実際に貼り付けてみると以下の通り。

TAG:NAME INSTANCEID INSTANCETYPE AZ PRIVATEIP PUBLICIP STATUS
dev-aaa1 i-xxxxxxxxxxxxxxxxx t2.micro ap-northeast-1a 172.31.x.187 Not assignment stopped
dev-bbb1 i-xxxxxxxxx t2.micro ap-northeast-1a 172.31.x.39 Not assignment stopped
hogehoge i-yyyyyyyyyyyyyyyyy t2.micro ap-northeast-1a 172.31.x.89 Not assignment stopped
dev-ccc1 i-zzzzzzzzz t2.medium ap-northeast-1a 172.31.x.139 Not assignment stopped
dev-ddd1 i-pppppppppp t2.micro ap-northeast-1a 172.31.x.117 52.198.32.108 running
dev-eee1 i-qqqqqqqqqqqqqq t2.micro ap-northeast-1a 172.31.x.28 Not assignment stopped

Backlog 記法も出力出来ると嬉しいけどもう少し研究が必要。

ということで

郷言語

難しいけど、ワンバイナリに出来るのはとても魅力的でデプロイの手順削減にだいぶん貢献出来ると思う。色々と覚えなければいけないこともあったりするけど、シェルスクリプトを作るような感覚で作ることが出来そうな気がする(気がするだけ)。

aws-sdk-go のドキュメント

このドキュメントの読み方がイマイチ解っていないのが致命的。

工夫したところ

func aws_ec2_client(profile string, region string) *ec2.EC2 {
    var config aws.Config
    if profile != "" {
        creds := credentials.NewSharedCredentials("", profile)
        config = aws.Config{Region: aws.String(region), Credentials: creds}
    } else {
        config = aws.Config{Region: aws.String(region)}
    }
    sess := session.New(&config)
    ec2_client := ec2.New(sess)
    return ec2_client
}

手元のパソコンから oreno-ec2 を叩く場合には Shared Credential の Profile 名を指定することが多いけど、EC2 上で叩く場合には大概の場合、IAM Role が付いているので Profile 名が指定されない場合を想定している。(より良い書き方があるかもしれないけど)

テスト

プログラムを書いたらテストまでしっかりと書きたいと思い続けて 100 年くらいたったけど、なかなかテストを書くという行為まで至れない。

2017 年 07 月 01 日(土)

YAPC::Fukuoka 2017

LINE Fukuoka も初めて訪れた。

途中までの参加だったけど、夏の暑さに負けないくらいの刺激を頂いたきがする。

ジョギングとか日課

は全てお休み。