DRYな備忘録

Don't Repeat Yourself.

【メモ】Slackチャンネルへの画像の投稿

参考

curl

% curl -XPOST "https://slack.com/api/files.upload" \
    -H "Content-Type: multipart/form-data" \
    -F file=@/Users/otiai10/Desktop/ritsu.jpeg \
    -F token=xoxb-123-456-xxxxxxxxx \
    -F channels=bot-dev \
    | jq
{
  "ok": true,
  "file": {
    "url_private": "https://files.slack.com/files-pri/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ritsu.jpeg",
    "url_private_download": "https://files.slack.com/files-pri/ABCDEFGHIJKLMNOPQRSTUVWXYZ/download/ritsu.jpeg",
    // いろいろ省略
}

DRY

【メモ】VPCエンドポイントについて

背景

  • EC2とS3が密に関係するソフトウェアを書いてるんですが、VPCエンドポイントの概念を知らなかったので、非常に悔やまれます。

資料

VPCエンドポイントが解決する問題

  • EC2インスタンスなどVPC内のサービスから、S3を参照するさい、InternetGatewayやNATを通って一度インターネットに出る必要がある
  • これを、VPCエンドポイントという概念を使って、インターネットに出ずに、AWSのネットワーク内でS3まで到達できるようになった
    • 具体的には、 S3のエンドポイントをDestinationとし、VPCエンドポイント(vpce-から始まるリソース)をTargetとするRouteをRouteTablesに追加することによって実現する
    • リージョンはまたげない
  • NATの負荷軽減、セキュリティの強化が期待できる

使い方の概要

概念的なところ。

  1. 確認用に、インターネットに出ていけないSubnetをつくる
    • のちにこれにsshして動作確認するので、必要なら、自宅なりオフィスのIPアドレスDestinationとしInternetGatewayをTargetに持つRouteだけは、追加しておく
  2. このSubnetの配下にEC2インスタンスを作成する
    • SecurityGroupはiptablesみたいなもので今回の検証とはレイヤーが違うので、検証環境からsshできるIn/Outを設定すればよい
  3. このEC2インスタンスsshする
    • あとで使うので、必要なら sudo yum install -y python-pip && pip install awscli とかしとく
  4. ping google.comとかやって、インターネットに出ていけないことを確認する
  5. aws s3 ls your-bucket などして無反応なことを確認する
    • なぜなら、EC2からS3は、デフォルトではインターネット経由だから
  6. VPCエンドポイントを作成し、このSubnetと紐付ける( ≒ RouteをRouteTablesに追加する)
  7. やはり、ping google.com は通らない
  8. しかし、aws s3 ls your-bucket は通る
    • なぜなら、EC2からS3への疎通はVPCエンドポイントが使われるようになったから

※ リージョン跨げないので、your-bucketはEC2と同リージョンである必要がある

DRYな備忘録として

Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂版

Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂版

【Go言語】aws-sdk-goを使ったVPC新規作成からEC2のsshまで

前回これをやったので、

otiai10.hatenablog.com

今回は、これをGoのSDKからやる。

結果だけくれ

はい

github.com

以下ペライチ全文

package main

import (
    "flag"
    "fmt"
    "log"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/ec2"
)

var (
    region string
    name   string
    clean  bool
)

func init() {
    flag.StringVar(&region, "region", "ap-northeast-1", "Region")
    flag.StringVar(&name, "name", "otiai10-sdk-test", "Name of VPC")
    flag.BoolVar(&clean, "clean", false, "Clean up created VPC")
    flag.Parse()
}

func main() {
    sess := session.New(&aws.Config{
        Region: aws.String(region),
    })
    client := ec2.New(sess)

    // Get VPC if exists
    vpcsout, err := client.DescribeVpcs(&ec2.DescribeVpcsInput{
        Filters: []*ec2.Filter{
            &ec2.Filter{Name: aws.String("tag:Name"), Values: aws.StringSlice([]string{name})},
        },
    })
    if err != nil {
        log.Fatalln("01", err)
    }

    if vpcs := vpcsout.Vpcs; len(vpcs) != 0 {
        fmt.Printf("%+v\n", vpcs[0])
        fmt.Printf("Total %d VPCs.\n", len(vpcs))
        if !clean {
            return // If exists, do nothing
        }
        // Clean up if "clean" flag is specified.
        if err := cleanupVpcs(client, vpcs); err != nil {
            log.Fatalln("01-clean", err)
        }
    }

    // Create because it doesn't exist
    createout, err := client.CreateVpc(&ec2.CreateVpcInput{
        CidrBlock: aws.String("10.0.0.0/24"),
    })
    if err != nil {
        log.Fatalln("02", err)
    }
    vpc := createout.Vpc
    fmt.Println("VPC created:", *vpc.VpcId)
    // Name this VPC
    _, err = client.CreateTags(&ec2.CreateTagsInput{
        Tags: []*ec2.Tag{
            {Key: aws.String("Name"), Value: aws.String(name)},
        },
        Resources: []*string{vpc.VpcId},
    })
    if err != nil {
        log.Fatalln("03", err)
    }

    // Create subnet
    subnetout, err := client.CreateSubnet(&ec2.CreateSubnetInput{
        AvailabilityZone: aws.String(region + "a"), // FIXME: hard coded
        CidrBlock:        aws.String("10.0.0.0/28"),
        VpcId:            vpc.VpcId,
    })
    if err != nil {
        log.Fatalln("04", err)
    }
    subnet := subnetout.Subnet
    fmt.Println("Subnet created:", *subnet.SubnetId)
    _, err = client.CreateTags(&ec2.CreateTagsInput{
        Tags: []*ec2.Tag{
            {Key: aws.String("Name"), Value: aws.String(name + "-sn")},
        },
        Resources: []*string{subnet.SubnetId},
    })
    if err != nil {
        log.Fatalln("05", err)
    }

    // Create InternetGateway
    gatewayout, err := client.CreateInternetGateway(&ec2.CreateInternetGatewayInput{})
    if err != nil {
        log.Fatalln("06", err)
    }
    gateway := gatewayout.InternetGateway
    fmt.Println("InternetGateway created:", *gateway.InternetGatewayId)
    _, err = client.CreateTags(&ec2.CreateTagsInput{
        Tags: []*ec2.Tag{
            {Key: aws.String("Name"), Value: aws.String(name + "-ig")},
        },
        Resources: []*string{gateway.InternetGatewayId},
    })
    if err != nil {
        log.Fatalln("07", err)
    }

    // Attach this InternetGateway to VPC
    _, err = client.AttachInternetGateway(&ec2.AttachInternetGatewayInput{
        InternetGatewayId: gateway.InternetGatewayId,
        VpcId:             vpc.VpcId,
    })
    if err != nil {
        log.Fatalln("08", err)
    }

    // Create RouteTables
    routetablesout, err := client.DescribeRouteTables(&ec2.DescribeRouteTablesInput{
        Filters: []*ec2.Filter{
            {Name: aws.String("vpc-id"), Values: []*string{vpc.VpcId}},
        },
    })
    if err != nil {
        log.Fatalln("09", err)
    }
    if len(routetablesout.RouteTables) == 0 {
        log.Fatalln("10", "No route table found on this VPC")
    }
    routetable := routetablesout.RouteTables[0]
    fmt.Println("RouteTable created:", *routetable.RouteTableId)
    _, err = client.CreateTags(&ec2.CreateTagsInput{
        Tags: []*ec2.Tag{
            {Key: aws.String("Name"), Value: aws.String(name + "-rt")},
        },
        Resources: []*string{routetable.RouteTableId},
    })
    if err != nil {
        log.Fatalln("11", err)
    }

    // Create Routing Rule on this RouteTables
    _, err = client.CreateRoute(&ec2.CreateRouteInput{
        DestinationCidrBlock: aws.String("0.0.0.0/0"),
        RouteTableId:         routetable.RouteTableId,
        GatewayId:            gateway.InternetGatewayId,
    })
    if err != nil {
        log.Fatalln("12", err)
    }
    fmt.Println("Route created")

    fmt.Println("Congrats! Everything is up!!")
}

func cleanupVpcs(client *ec2.EC2, vpcs []*ec2.Vpc) error {
    for _, vpc := range vpcs {
        if err := cleanupVpc(client, vpc); err != nil {
            return err
        }
    }
    return nil
}
func cleanupVpc(client *ec2.EC2, vpc *ec2.Vpc) error {

    // Delete InternetGateway
    igws, err := client.DescribeInternetGateways(&ec2.DescribeInternetGatewaysInput{
        Filters: []*ec2.Filter{
            {Name: aws.String("tag:Name"), Values: aws.StringSlice([]string{name + "-ig"})},
        },
    })
    if err != nil {
        return err
    }
    fmt.Printf("%d InternetGateways found,\n", len(igws.InternetGateways))
    for _, ig := range igws.InternetGateways {
        if _, err := client.DetachInternetGateway(&ec2.DetachInternetGatewayInput{
            InternetGatewayId: ig.InternetGatewayId,
            VpcId:             vpc.VpcId,
        }); err != nil {
            return err
        }
        if _, err := client.DeleteInternetGateway(&ec2.DeleteInternetGatewayInput{
            InternetGatewayId: ig.InternetGatewayId,
        }); err != nil {
            return err
        }
    }
    fmt.Println("and deleted.")

    // Delete Subnets
    snts, err := client.DescribeSubnets(&ec2.DescribeSubnetsInput{
        Filters: []*ec2.Filter{
            {Name: aws.String("tag:Name"), Values: aws.StringSlice([]string{name + "-sn"})},
        },
    })
    if err != nil {
        return err
    }
    fmt.Printf("%d Subnets found,\n", len(snts.Subnets))
    for _, sn := range snts.Subnets {
        if _, err := client.DeleteSubnet(&ec2.DeleteSubnetInput{
            SubnetId: sn.SubnetId,
        }); err != nil {
            return err
        }
    }
    fmt.Println("and deleted.")

    // Delete VPC
    if _, err := client.DeleteVpc(&ec2.DeleteVpcInput{
        VpcId: vpc.VpcId,
    }); err != nil {
        return err
    }
    fmt.Printf("VPC %s deleted.", *vpc.VpcId)

    return err
}

雑感

DRYな備忘録として

Amazon Web Services実践入門 (WEB+DB PRESS plus)

Amazon Web Services実践入門 (WEB+DB PRESS plus)

Goならわかるシステムプログラミング

Goならわかるシステムプログラミング

aws cli を使ったVPCの新規作成からEC2へのsshまで

まずWebコンソールでゴールの確認

  1. VPCの作成
  2. Subnetの作成
  3. InternetGatewayの作成
  4. VPCに上記3のInternetGatewayをアタッチ
  5. SubnetのRouteTableに上記3のInternetGatewayに紐付いたルールを追加
  6. 上記1のVPC内で、上記2のSubnet配下に、EC2インスタンスをつくる
  7. (適宜、必要があればSecurityGroupのInboundをいじったりする)
  8. sshできる。

ここまでやった。できた。

% ssh -i ~/Desktop/otiai10.tokyo.pem ec2-user@54.249.68.183

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-10-0-0-11 ~]$ exit
logout
Connection to 54.249.68.182 closed.

これをゴールとして、以下、これをaws cliだけでやっていく。

まずはお掃除する。

% aws ec2 describe-vpcs \
  --filters Name=tag:Name,Values=otiai10-test-web \
  | jq .Vpcs[].VpcId

% aws ec2 delete-vpc --vpc-id vpc-374f0d50

An error occurred (DependencyViolation) when calling the DeleteVpc operation: The vpc 'vpc-374f0d50' has dependencies and cannot be deleted.

% aws ec2 delete-vpc help

NAME
       delete-vpc -

DESCRIPTION
       Deletes  the  specified VPC. You must detach or delete all gateways and
       resources that are associated with the VPC before you  can  delete  it.
       For  example,  you  must  terminate  all  instances running in the VPC,
       delete all security groups associated with the VPC (except the  default
       one),  delete  all  route  tables  associated  with the VPC (except the
       default one), and so on.

まあそうですよね。消すべき要素としては、

  1. EC2インスタンス
  2. Subnet
  3. InternetGateway
  4. 最後に、VPC

という感じだろうか。

# EC2インスタンスIDの取得
% aws ec2 describe-instances \
  --filters Name=tag:Name,Values='otiai10 Test' \
  | jq .Reservations[].Instances[].InstanceId

# セキュリティグループの取得
% aws ec2 describe-instances \
  --filters Name=tag:Name,Values='otiai10 Test' \
  | jq .Reservations[].Instances[].SecurityGroups

# EC2インスタンスの削除
% aws ec2 terminate-instances \
  --instance-ids i-0acd5d33bb4196314

# セキュリティグループの削除
% aws ec2 delete-security-group \
  --group-id sg-7fb2ec07
# Subnet IDの取得
% aws ec2 describe-subnets \
  --filters Name=tag:Name,Values=otiai10-test-web-example \
  | jq .Subnets[].SubnetId

# Subnetの削除
% aws ec2 delete-subnet \
  --subnet-id subnet-39020970
# InternetGatewayのIDの取得
% aws ec2 describe-internet-gateways \
  --filters Name=tag:Name,Values=otiai10-test-web-ig \
  | jq .InternetGateways[].InternetGatewayId

# InternetGatewayの削除
% aws ec2 delete-internet-gateway \
  --internet-gateway-id igw-6de6b009

An error occurred (DependencyViolation) when calling the DeleteInternetGateway operation:
The internetGateway 'igw-6de6b009' has dependencies and cannot be deleted.

おっと。なんだ。detachか?

# VPC IDの取得
% aws ec2 describe-vpcs \
  --filters Name=tag:Name,Values=otiai10-test-web \
  | jq .Vpcs[].VpcId

# InternetGatewayをVPCからdetach
% aws ec2 detach-internet-gateway \
  --internet-gateway-id igw-6de6b009 \
  --vpc-id vpc-374f0d50

# VPCの削除
% aws ec2 delete-vpc --vpc-id vpc-374f0d50

# InternetGatewayの削除
% aws ec2 delete-internet-gateway \
  --internet-gateway-id igw-6de6b009

awscliを使ったVPCの新規作成からEC2へのssh可能状態まで

VPCを作成。

% aws ec2 create-vpc --cidr-block 10.0.0.0/16 | jq .Vpc.VpcId
"vpc-b7e4acd0"
% aws ec2 create-tags \
   --resources vpc-b7e4acd0 \
   --tags Key=Name,Value=otiai10-test

% aws ec2 describe-vpcs \
  --filter Name=tag:Name,Values=otiai10-test 

# 取れてることを確認

Subnetの作成。

% aws ec2 create-subnet \
  --availability-zone ap-northeast-1a \
  --cidr-block 10.0.0.0/18 \
  --vpc-id vpc-b7e4acd0

# 一応名前つけとく
% aws ec2 create-tags \
  --resources subnet-eb6076a2 \
  --tags Key=Name,Value=otiai10-sn

InternetGatewayの作成。

% aws ec2 create-internet-gateway

# 一応名前つけとく
% aws ec2 create-tags \
  --resources igw-a9beedcd \
  --tags Key=Name,Value=otiai10-ig

InternetGatewayをVPCにアタッチ。

% aws ec2 attach-internet-gateway \
  --vpc-id vpc-b7e4acd0 \
  --internet-gateway-id igw-a9beedcd

MainのRouteTableの確認。

% aws ec2 describe-route-tables \
  | jq '.RouteTables[] | select(.VpcId =="vpc-b7e4acd0")'

ここにRouteの追加。

% aws ec2 create-route \
  --destination-cidr-block 0.0.0.0/0 \
  --route-table-id rtb-57a20331 \
  --gateway-id igw-a9beedcd

これで一応要件を満たしたVPCvpc-b7e4acd0 )ができたと思う。

動作確認

SecurityGroupの作成。

% aws ec2 create-security-group \
  --group-name otiai10-ssh \
  --description ssh-from-office \
  --vpc-id vpc-b7e4acd0

# オフィスからのSSHを開ける
% aws ec2 authorize-security-group-ingress \
  --group-id sg-ab5550d3 \
  --protocol tcp \
  --port 22 \
  --cidr 106.180.6.34/32

EC2インスタンスの作成

% aws ec2 run-instances \
  --instance-type t2.nano \
  --image-id ami-e99f4896 \
  --key-name otiai10.tokyo \
  --security-group-ids sg-ab5550d3 \
  --subnet-id subnet-eb6076a2 \
  --associate-public-ip-address

EC2インスタンスへのSSH

% ssh \
  -i ~/.ssh/aws/otiai10.tokyo.pem \
  ec2-user@52.197.24.227


       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-10-0-8-208 ~]$
[ec2-user@ip-10-0-8-208 ~]$ uname -a
Linux ip-10-0-8-208.ap-northeast-1.compute.internal 4.14.47-64.38.amzn2.x86_64 #1 SMP Mon Jun 18 22:33:07 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[ec2-user@ip-10-0-8-208 ~]$ exit
logout
Connection to 52.197.24.227 closed.
%
%

できた。帰りはしんどいのでWebコンソールでお掃除した。

DRYな備忘録として

Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂版

Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂版

Amazon Web Servicesではじめる新米プログラマのためのクラウド超入門 (CodeZine BOOKS)

Amazon Web Servicesではじめる新米プログラマのためのクラウド超入門 (CodeZine BOOKS)

CWLでHello, World。

CWLって何

的なものについては、このあたりをご参考ください。Web系プログラマ諸兄の99%は縁が無いかと思います。

参考

ログ

% mkdir -p ~/tmp/cwl-playground/hello-world
% cd ~/tmp/cwl-playground/hello-world
% vi hello.cwl
% vi job.yml

hello.cwl の中身

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: echo
inputs:
    message:
        type: string
        inputBinding:
            position: 1
outputs: []

job.yml の中身

message: Hello World!!

ほんで、

% cwltool ./hello.cwl ./job.yml

とすると

/usr/local/bin/cwltool 1.0.20180622214234
Resolved './hello.cwl' to 'file:///root/hello-world/hello.cwl'
[job hello.cwl] /tmp/tmpGt_fgK$ echo \
    'Hello, World!!'
Hello, World!!
[job hello.cwl] completed success
{}
Final process status is success

となる。

まとめ

これ

github.com

雑感

  • alpineでcwltoolインストールしてもなんかエラー吐いてるので調査

DRYな備忘録として

【Go言語】aws-sdk-goで Instance Profile の作成

CLIでやるのはこれ↓でやって概念理解したので、

otiai10.hatenablog.com

SDK使って同じことをコードからやる。

package main

import (
    "bytes"
    "encoding/json"
    "flag"
    "fmt"
    "time"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/iam"
)

const (
    arnPolicyAmazonS3FullAccess = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
)

var (
    region string
    name   string
)

func init() {
    flag.StringVar(&region, "region", "ap-northeast-1", "Region")
    flag.StringVar(&name, "role-name", "testtest", "Role and profile name")
    flag.Parse()
}
func main() {

    // 0) APIクライアントの初期化
    sess := session.New(&aws.Config{
        Region: aws.String(region),
    })
    client := iam.New(sess)

    // 1) Roleをつくる
    assumepolicy := map[string]interface{}{
        "Version": "2012-10-17",
        "Statement": []map[string]interface{}{
            {
                "Sid":       "",
                "Effect":    "Allow",
                "Action":    "sts:AssumeRole",
                "Principal": map[string]string{"Service": "ec2.amazonaws.com"},
            },
        },
    }
    buf := bytes.NewBuffer(nil)
    if err := json.NewEncoder(buf).Encode(assumepolicy); err != nil {
        panic(err)
    }

    createRoleOutput, err := client.CreateRole(&iam.CreateRoleInput{
        Path:                     aws.String("/"),
        RoleName:                 aws.String(name),
        AssumeRolePolicyDocument: aws.String(buf.String()),
        Description:              aws.String(time.Now().Format(time.RFC3339)),
    })
    if err != nil {
        panic(err)
    }
    role := createRoleOutput.Role

    // 2) Policyをつくる
    //    ... というのは割愛します。今回は既存のもの使おう。
    //        具体的には、 arn:aws:iam::aws:policy/AmazonS3FullAccess です。

    // 3) Role に Policy を attach する
    _, err = client.AttachRolePolicy(&iam.AttachRolePolicyInput{
        PolicyArn: aws.String(arnPolicyAmazonS3FullAccess),
        RoleName:  role.RoleName,
    })
    if err != nil {
        panic(err)
    }

    // 4) Instance Profile をつくる
    instanceprofileCreateOutput, err := client.CreateInstanceProfile(&iam.CreateInstanceProfileInput{
        InstanceProfileName: role.RoleName, // めんどくさいのでRole名と同じにします
    })
    if err != nil {
        panic(err)
    }
    instanceprofile := instanceprofileCreateOutput.InstanceProfile

    // 5) Instance Profile に Role を追加する
    _, err = client.AddRoleToInstanceProfile(&iam.AddRoleToInstanceProfileInput{
        InstanceProfileName: instanceprofile.InstanceProfileName,
        RoleName:            role.RoleName,
    })
    if err != nil {
        panic(err)
    }

    // 成果物
    fmt.Printf("%+v\n", instanceprofile)
}

実行

% go run main.go
{
  Arn: "arn:aws:iam::111222333444555666:instance-profile/testtest",
  CreateDate: 2018-06-05 08:18:09.494 +0000 UTC,
  InstanceProfileId: "AIPAJDNEGOMABCDEFGHIJK",
  InstanceProfileName: "testtest",
  Path: "/"
}

雑感

DRYな備忘録として

Goならわかるシステムプログラミング

Goならわかるシステムプログラミング

Amazon Web Services パターン別構築・運用ガイド 改訂第2版 (Informatics&IDEA)

Amazon Web Services パターン別構築・運用ガイド 改訂第2版 (Informatics&IDEA)

aws cli で IAM Instance Profile をつくってEC2に適用する

Role つくる

% aws iam get-role --role-name foobar
% aws iam create-role --role-name foobar --assume-role-policy-document file://assume-role-policy.json
% aws iam get-role --role-name foobar

assume-role-policy.json というのは、

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

Policy つくる

arn:aws:iam::aws:policy/AmazonS3FullAccess など既存のものを使ってもよい。

% aws iam create-policy --policy-name testpolicy --policy-document file://testpolicy.json
% aws iam list-policies --query Policies[?PolicyName==\'testpolicy\']
% export POLICY_ARN=`aws iam list-policies --query Policies[?PolicyName==\'testpolicy\'].Arn --output text`
% echo $POLICY_ARN

testpolicy.json というのは、

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::*"
            ]
        }
    ]
}

Role に Policy を attach する

% aws iam attach-role-policy --role-name foobar --policy-arn $POLICY_ARN
% aws iam list-attached-role-policies --role-name foobar

Instance Profile をつくる

% aws iam create-instance-profile --instance-profile-name hogefuga
% aws iam get-instance-profile --instance-profile-name hogefuga

Instance Profile に Role を attach する

% aws iam add-role-to-instance-profile --instance-profile-name hogefuga --role-name foobar
% aws iam get-instance-profile --instance-profile-name hogefuga

以上でいけてるはず。

確認: 作成した Instance Profile を利用してみる

Negative Control: 作成したInstance Profileを使わずにEC2をローンチする

% aws ec2 run-instances \
--region ap-northeast-1 \
--instance-type t2.nano \
--associate-public-ip-address \
--key-name otiai10-test.tokyo \
--image-id ami-92df37ed \
--security-group-ids sg-8fec68f7
[ec2-user@ip-172-31-26-230 ~]$ aws s3 ls s3://otiai10-test-bucket
Unable to locate credentials. You can configure credentials by running "aws configure".

Positive: 作成したInstance Profileを付与してEC2をローンチする

% aws ec2 run-instances \
--region ap-northeast-1 \
--instance-type t2.nano \
--associate-public-ip-address \
--key-name otiai10-test.tokyo \
--image-id ami-92df37ed \
--security-group-ids sg-8fec68f7 \
--iam-instance-profile Name=hogefuga
[ec2-user@ip-172-31-21-74 ~]$ aws s3 ls s3://otiai10-test-bucket
                           PRE aaa/
                           PRE bbb/
                           PRE xxx/
[ec2-user@ip-172-31-21-74 ~]$ touch perm-test-example.txt
[ec2-user@ip-172-31-21-74 ~]$ aws s3 cp perm-test-example.txt s3://otiai10-test-bucket/example.txt
upload failed: ./perm-test-example.txt to s3://otiai10-test-bucket/example.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

当該 Instance Profile を付与したインスタンスだけが、S3へ指定した権限を持つことが確認できた。

後片付け

% aws ec2 terminate-instances --instance-ids i-00dd9b9d9310be741 i-0f78bdb6bf62cc5c5
% aws iam remove-role-from-instance-profile --instance-profile-name hogefuga --role-name foobar
% aws iam delete-instance-profile --instance-profile-name hogefuga
% aws iam detach-role-policy --role-name foobar --policy-arn $POLICY_ARN
% aws iam delete-role --role-name foobar

雑感

  • IAM Instance Profile まわりをCLIでやるのはたいへんだるい

DRYな備忘録として

合格対策 AWS認定ソリューションアーキテクト - アソシエイト

合格対策 AWS認定ソリューションアーキテクト - アソシエイト

Amazon Web Services パターン別構築・運用ガイド 改訂第2版 (Informatics&IDEA)

Amazon Web Services パターン別構築・運用ガイド 改訂第2版 (Informatics&IDEA)

AWSによるサーバーレスアーキテクチャ

AWSによるサーバーレスアーキテクチャ