DRYな備忘録

Don't Repeat Yourself.

Go GCP Client で ComputeEngine インスタンスの作成・取得

やりたいことを gcloud SDK で確認

% gcloud compute instances create \
    --project otiai10-sandbox \
    --zone asia-northeast1-a \
    testetst

% gcloud compute instances list \
    --project otiai10-sandbox \
    --filter zone:asia-northeast1-a

Go GCP Client でだいたい同じことやる

これです

github.com

以下全文

package main

import (
    "context"
    "flag"
    "fmt"
    "log"
    "time"

    "google.golang.org/api/googleapi"

    "github.com/otiai10/debug"
    "golang.org/x/oauth2/google"
    compute "google.golang.org/api/compute/v1"
)

var (
    project string
    zone    string
    name    string
)

func init() {
    flag.StringVar(&project, "project", "otiai10-sandbox", "Project name on GCP")
    flag.StringVar(&zone, "zone", "asia-northeast1-a", "Zone of GCP")
    flag.StringVar(&name, "name", "test-instance", "Instance name to create")
    flag.Parse()
}

func main() {

    ctx := context.Background()
    client, err := google.DefaultClient(ctx, compute.ComputeScope)
    if err != nil {
        debug.Fatalln(err)
    }

    service, err := compute.New(client)
    if err != nil {
        debug.Fatalln(err)
    }

    // Read
    instance, err := service.Instances.Get(project, zone, name).Do()

    if err == nil && instance != nil {
        // Delete
        log.Printf("Instance found, trying to delete.")
        _, err := service.Instances.Delete(project, zone, name).Do()
        if err != nil {
            debug.Fatalln(err)
        }
        for count := 0; ; count++ {
            fmt.Print(".")
            _, err := service.Instances.Get(project, zone, name).Do()
            if apierror, ok := err.(*googleapi.Error); ok && apierror.Code == 404 {
                fmt.Print("\n")
                break
            }
            time.Sleep(2 * time.Second)
            if count > 15 {
                debug.Fatalln("Couldn't wait for instance deletion ;(")
            }
        }
        log.Printf("Deleted: %v", name)
    } else if apierror, ok := err.(*googleapi.Error); !ok || apierror.Code != 404 {
        debug.Fatalln(err)
    }

    // Create
    instance = &compute.Instance{
        Description: "This is test",
        Name:        name,
        MachineType: fmt.Sprintf("zones/%s/machineTypes/n1-standard-1", zone),
        NetworkInterfaces: []*compute.NetworkInterface{
            &compute.NetworkInterface{
                Network: fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/global/networks/default", project),
            },
        },
        Disks: []*compute.AttachedDisk{
            &compute.AttachedDisk{
                AutoDelete: true,
                Boot:       true,
                Type:       "PERSISTENT",
                InitializeParams: &compute.AttachedDiskInitializeParams{
                    SourceImage: "projects/debian-cloud/global/images/debian-9-stretch-v20180806",
                    DiskSizeGb:  10,
                },
            },
        },
    }
    _, err = service.Instances.Insert(project, zone, instance).Do()
    if err != nil {
        debug.Fatalln(err)
    }

    log.Println("Created:", instance.Name)
}

雑感

  • AWSより概念が細分化されており、SDKとしての Hello World まで行くのはわりと大変だったけど、一度動いてしまったら、概念が明確で、とても使いやすい印象

DRYな備忘録として

クラウドエンジニア養成読本[クラウドを武器にするための知識&実例満載! ] (Software Design plusシリーズ)

クラウドエンジニア養成読本[クラウドを武器にするための知識&実例満載! ] (Software Design plusシリーズ)

【メモ】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)