先日、Amazon 本社で AWS スタートアップの説明を聞く機会があった。そこで「最近では踏み台に Cloud9 を使っている方も」という話を聞いたので「本当に踏み台として使えるのか」「Terraform との相性はどうなのか」というのを確認してみた。なお、Cloud9 には新規に EC2 インスタンス を作成するタイプと既存の EC2 インスタンス などに Cloud9 IDE をインストールして Cloud9 environment として使う SSH タイプもあるが後者については触れない。
2019年7月15日時点で書く内容が増えすぎたため一旦公開していますが内容に一部誤りがある可能性があります。
AWS Cloud9 とはAWS Cloud9 はブラウザで使えるクラウド 上の IDE 。本来は開発目的で利用するものなんだろうが EC2 インスタンス を使っているので普通に踏み台として EC2 を構築するのとあまり変わらない。実際、既存の EC2 インスタンス に Cloud9 IDE をインストールしてそのまま「environment」として使うこともできる。
一般的な SSH 接続を中継する方法以外に Cloud9 IDE のターミナルからプライベートネットワークにあるインスタンス に SSH 接続をするという選択肢がある。AWS マネジメントコンソールにアクセスでき、対象の「environment」でターミナルを使う権限があるユーザであれば SSH クライアントなしでプライベートネットワークに配置されているインスタンス にアクセスができる。ブラウザ上でファイル転送もできるので大抵のことは Cloud9 IDE 上でできるだろう。
他にも Cloud9 を使うメリットとしては以下のようなことが考えられる。
membership というもので IDE にアクセスできる(=ターミナルを利用できる)ユーザを管理することができる。 (Cloud9 IDE からし かアクセス出来ないと思われる)セキュリティグループを自動的に作成してくれる。名前は aws-cloud9-環境名-乱数
のような書式。 インアクティブな状態が続いた場合の自動シャットダウンを「30 分」「1 時間」「4 時間」「1 日」「1 週間」「なし」から設定することができる。踏み台用のインスタンス のコストを抑えることができる。 「お、これは結構使えるのでは?」と思ったが、試しているうちにデメリットも色々と出てきた。詳しくは後述するが、だいたい以下のような点。
Cloud9 用のインスタンス を作成したらサーバに接続するための秘密鍵 を保存しておく必要がある。 一般的な SSH 接続を中継する踏み台として利用する場合、セキュリティグループの編集が必要になったり、EIP を設定したりする必要がああるが自動化が難しい。 現時点での個人的な感想は「踏み台として『使える』か『使えない』かなら『使える』が、何か中途半端」といった感じ。
では孤独のハンズオンで色々と試していく。
Cloud9 environment の作成 Cloud9 では environment (以下、「Cloud9 environment」とする)と membership でアクセス制限を行っている。作成した Cloud9 environment の membership に IAM ユーザやロールを read-only
または read-write
のいずれかの権限で追加することによって複数のユーザで Cloud9 environment を共有することができるようになっている。
AWS マネジメントコンソールの Cloud9 メニューでは以下のように environment の種類が分かれている。
Your environment Owner が自身の ARN で登録されている Cloud9 environment が表示される。AWS マネジメントコンソールから作成した場合は必ずこちらに登録される。 Shared with you 対象の Cloud9 environment の membership に自身の ARN が read-only
または read-write
権限で登録されている Cloud9 environment が表示される。 Account Environments AWS アカウントに登録されている Cloud9 environment が表示される。自身が Owner の Cloud9 environment 以外に、Owner でもなく membership でも登録されていない Cloud9 environment も表示される。Terraform や AWS CLI で Owner の ARN を指定しなかった場合はここにのみ表示される。
membership には read-only
と read-write
以外に owner
があり、これは Cloud9 environment 作成時に自動的に作成される membership であり変更はできない。
AWS マネジメントコンソール、Terraform、AWS CLI で Cloud9 environment 作成時の挙動が異なるので以下にまとめておく。
AWS マネジメントコンソールから Cloud9 environment を作成する「Name」は必須だが「Description」は任意。既に同名の Cloud9 environment が存在する場合は作成できない。(Owner が異なる場合は作成可能)
AWS Cloud9
インスタンス タイプや配置する VPC 、サブネットなどを選択する。インスタンス タイプは「Other instance type」を選択すれば好きなものを選ぶことができる。執筆時点ではここの「Amazon Linux 」は「Amazon Linux 2」ではない。VPC やサブネットはデフォルトでは「デフォルト VPC 」と「デフォルトサブネット」を使うようになっている。実際にはプロジェクト用に作成した VPC とサブネットに配置すると思うが、ここで気をつけなければならないのは Cloud9 environment を配置するサブネットはパブリックサブネットでなければならない 。Cloud9 によって自動的に作成されるセキュリティグループを見ればわかるがインバウンドルールに Cloud9 用に予約されたネットワークからの 22 番接続を許可する設定が追加される。Cloud9 environment への接続へはグローバルから行われることになるため NAT ゲートウェイ の有無に関わらずプライベートサブネットへ配置すると Cloud9 IDE にアクセスできなくなる。
AWS Cloud9 - Create environment
設定内容を確認して[Create environment]ボタンをクリックする。
AWS Cloud9 - Create environment
Cloud9 用のインスタンス 作成が行われて接続画面に移行する。Cloud9 用の AMI から作成されているのでだいたい 60 秒もあれば使えるようになる。
AWS Cloud9 - Cloud9 IDE
Cloud9 で作成される EC2 インスタンス とセキュリティグループは CloudFormation によって作成されているのでまずは CloudFormation のスタックを確認する。スタック名は aws-cloud9-{Cloud9環境名}-{Cloud9環境ID}
となっている。Cloud9 environment の ID は Cloud9 IDE の URL か AWS CLI の cloud9 list-environments
で調べることができる。
aws cloudformation describe-stacks \ --stack-name aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
{ "Stacks ": [ { "StackId ": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ",
"StackName ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ",
"CreationTime ": "2019-07-14T14:59:45.535Z ",
"RollbackConfiguration ": {} ,
"StackStatus ": "CREATE_COMPLETE ",
"DisableRollback ": false ,
"NotificationARNs ": [] ,
"Tags ": [ { "Key ": "aws:cloud9:environment ",
"Value ": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
} ,
{ "Key ": "aws:cloud9:owner ",
"Value ": "XXXXXXXXXXXXXXXXXXXXX:john "
} ] ,
"EnableTerminationProtection ": false } ] } スタックのリソースを確認する。
Terminal
aws cloudformation describe-stack-resources --stack-name aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ここから EC2 インスタンス の ID とセキュリティグループの ID がわかる。
Result
{ "StackResources ": [ { "StackName ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ",
"StackId ": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ",
"LogicalResourceId ": "Instance ",
"PhysicalResourceId ": "i-xxxxxxxxxxxxxxxxx ",
"ResourceType ": "AWS::EC2::Instance ",
"Timestamp ": "2019-07-14T15:00:31.775Z ",
"ResourceStatus ": "CREATE_COMPLETE "
} ,
{ "StackName ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ",
"StackId ": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ",
"LogicalResourceId ": "InstanceSecurityGroup ",
"PhysicalResourceId ": "sg-xxxxxxxxxxxxxxxxx ",
"ResourceType ": "AWS::EC2::SecurityGroup ",
"Timestamp ": "2019-07-14T14:59:55.347Z ",
"ResourceStatus ": "CREATE_COMPLETE "
} ] }
セキュリティグループは aws-cloud9-{Cloud9環境名}-{Cloud9環境ID}-InstanceSecurityGroup-{乱数}
という名前で作成されているので、GroupName
かタグ値で CloudFormation のスタック名をフィルタリングすればすぐ出てくるだろう。
Terminal
aws ec2 describe-security-groups --filters ' Name=group-name,Values=aws-cloud9-foo-* '
セキュリティグループのインバウンドルールには Cloud9 で予約されていると思われるネットワークアドレスが二つ登録されている。
Result
{ "SecurityGroups ": [ { "Description ": "Security group for AWS Cloud9 environment aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ",
"GroupName ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-InstanceSecurityGroup-XXXXXXXXXXXXX ",
"IpPermissions ": [ { "FromPort ": 22 ,
"IpProtocol ": "tcp ",
"IpRanges ": [ { "CidrIp ": "18.179.48.96/27 "
} ,
{ "CidrIp ": "18.179.48.128/27 "
} ] ,
"Ipv6Ranges ": [] ,
"PrefixListIds ": [] ,
"ToPort ": 22 ,
"UserIdGroupPairs ": [] } ] ,
"OwnerId ": "000000000000 ",
"GroupId ": "sg-xxxxxxxxxxxxxxxxx ",
"IpPermissionsEgress ": [ { "IpProtocol ": "-1 ",
"IpRanges ": [ { "CidrIp ": "0.0.0.0/0 "
} ] ,
"Ipv6Ranges ": [] ,
"PrefixListIds ": [] ,
"UserIdGroupPairs ": [] } ] ,
"Tags ": [ { "Key ": "aws:cloud9:owner ",
"Value ": "XXXXXXXXXXXXXXXXXXXXX:john "
} ,
{ "Key ": "aws:cloudformation:stack-name ",
"Value ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
} ,
{ "Key ": "aws:cloud9:environment ",
"Value ": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
} ,
{ "Key ": "aws:cloudformation:logical-id ",
"Value ": "InstanceSecurityGroup "
} ,
{ "Key ": "aws:cloudformation:stack-id ",
"Value ": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx "
} ] ,
"VpcId ": "vpc-xxxxxxxx "
} ] }
EC2 インスタンス も同様。
Terminal
aws describe-instances --filters ' Name=tag-key,Values=Name ' ' Name=tag-value,Values=aws-cloud9-foo-* '
{ "Reservations ": [ { "Groups ": [] ,
"Instances ": [ { "AmiLaunchIndex ": 0 ,
"ImageId ": "ami-0872d0e3184cfc976 ",
"InstanceId ": "i-xxxxxxxxxxxxxxxxx ",
"InstanceType ": "t2.micro ",
"LaunchTime ": "2019-07-14T14:59:58.000Z ",
"Monitoring ": { "State ": "disabled "
} ,
"Placement ": { "AvailabilityZone ": "ap-northeast-1a ",
"GroupName ": "",
"Tenancy ": "default "
} ,
"PrivateDnsName ": "ip-172-31-40-231.ap-northeast-1.compute.internal ",
"PrivateIpAddress ": "172.31.40.231 ",
"ProductCodes ": [] ,
"PublicDnsName ": "ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com ",
"PublicIpAddress ": "00.000.000.000 ",
"State ": { "Code ": 16 ,
"Name ": "running "
} ,
"StateTransitionReason ": "",
"SubnetId ": "subnet-xxxxxxxx ",
"VpcId ": "vpc-xxxxxxxx ",
"Architecture ": "x86_64 ",
"BlockDeviceMappings ": [ { "DeviceName ": "/dev/xvda ",
"Ebs ": { "AttachTime ": "2019-07-14T14:59:59.000Z ",
"DeleteOnTermination ": true ,
"Status ": "attached ",
"VolumeId ": "vol-xxxxxxxxxxxxxxxxx "
} } ] ,
"ClientToken ": "aws-c-Insta-XXXXXXXXXXXX ",
"EbsOptimized ": false ,
"EnaSupport ": true ,
"Hypervisor ": "xen ",
"NetworkInterfaces ": [ { "Association ": { "IpOwnerId ": "amazon ",
"PublicDnsName ": "ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com ",
"PublicIp ": "00.000.000.000 "
} ,
"Attachment ": { "AttachTime ": "2019-07-14T14:59:58.000Z ",
"AttachmentId ": "eni-attach-xxxxxxxxxxxxxxxxx ",
"DeleteOnTermination ": true ,
"DeviceIndex ": 0 ,
"Status ": "attached "
} ,
"Description ": "",
"Groups ": [ { "GroupName ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-InstanceSecurityGroup-XXXXXXXXXXXXX ",
"GroupId ": "sg-xxxxxxxxxxxxxxxxx "
} ] ,
"Ipv6Addresses ": [] ,
"MacAddress ": "xx:xx:xx:xx:xx:xx ",
"NetworkInterfaceId ": "eni-xxxxxxxxxxxxxxxxx ",
"OwnerId ": "000000000000 ",
"PrivateDnsName ": "ip-172-31-40-231.ap-northeast-1.compute.internal ",
"PrivateIpAddress ": "172.31.40.231 ",
"PrivateIpAddresses ": [ { "Association ": { "IpOwnerId ": "amazon ",
"PublicDnsName ": "ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com ",
"PublicIp ": "00.000.000.000 "
} ,
"Primary ": true ,
"PrivateDnsName ": "ip-172-31-40-231.ap-northeast-1.compute.internal ",
"PrivateIpAddress ": "172.31.40.231 "
} ] ,
"SourceDestCheck ": true ,
"Status ": "in-use ",
"SubnetId ": "subnet-xxxxxxxx ",
"VpcId ": "vpc-xxxxxxxx "
} ] ,
"RootDeviceName ": "/dev/xvda ",
"RootDeviceType ": "ebs ",
"SecurityGroups ": [ { "GroupName ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-InstanceSecurityGroup-XXXXXXXXXXXXX ",
"GroupId ": "sg-xxxxxxxxxxxxxxxxx "
} ] ,
"SourceDestCheck ": true ,
"Tags ": [ { "Key ": "aws:cloudformation:logical-id ",
"Value ": "Instance "
} ,
{ "Key ": "Name ",
"Value ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
} ,
{ "Key ": "aws:cloud9:environment ",
"Value ": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
} ,
{ "Key ": "aws:cloudformation:stack-id ",
"Value ": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx "
} ,
{ "Key ": "aws:cloud9:owner ",
"Value ": "XXXXXXXXXXXXXXXXXXXXX:john "
} ,
{ "Key ": "aws:cloudformation:stack-name ",
"Value ": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
} ] ,
"VirtualizationType ": "hvm ",
"CpuOptions ": { "CoreCount ": 1 ,
"ThreadsPerCore ": 1 } } ] ,
"OwnerId ": "000000000000 ",
"RequesterId ": "000000000000 ",
"ReservationId ": "r-xxxxxxxxxxxxxxxxx "
} ] } いずれもタグに Cloud9 environment の ID が入っているのでフィルタリングはしやすい。
Cloud9 environment の menbership について学ぶ AWS マネジメントコンソールから Cloud9 environment を作成した場合は現在の IAM ユーザやロールの ARN が Owner として設定されるようになっている。
Terminal
aws cloud9 describe-environments \ --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Result
{ "environments ": [ { "id ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"name ": "AWS Management Console ",
"description ": "",
"type ": "ec2 ",
"arn ": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"ownerArn ": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john "
} ] }
上記の Cloud9 environment の membership がどうなっているか確認してみる。
Terminal
aws cloud9 describe-environment-memberships \ --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Result
{ "memberships ": [ { "permissions ": "owner ",
"userId ": "XXXXXXXXXXXXXXXXXXXXX:john ",
"userArn ": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john ",
"environmentId ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"lastAccess ": 1562846115.0 } ] }
memberships
が配列になっていることからもわかるが membership には owner
以外に read-only
や read-write
といった権限で複数のユーザを登録することができるようになっている。
Cloud9 environment と membership の関連性 Cloud9 environment の権限には owner
、read-only
、read-write
の 3 種類がある。AWS マネジメントコンソールから Cloud9 environment を作成した場合、owner
には現在の IAM ユーザやロールが設定される。owner
は当然のことながら変更や削除などすべての操作を行うことができる。
Cloud9 environment には membership というものがあり、この membership をカスタマイズすることで environment を他のユーザと共有できるようになっている。現状の AWS マネジメントコンソールには membership を操作する画面は無く、Cloud9 IDE 内の共有設定で行うようになっている。
AWS Cloud9 IDE
Cloud9 environment を AWS マネジメントコンソール、Terraform、AWS CLI からownerArn を指定せずに それぞれ作成すると以下のようになる。なお、AWS マネジメントコンソールでは ownerArn の指定方法が無いため Owner には自動的に現在のユーザに設定される。
{ "environments ": [ { "id ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"name ": "AWS Management Console ",
"description ": "",
"type ": "ec2 ",
"arn ": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"ownerArn ": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john "
} ,
{ "id ": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ",
"name ": "Terraform ",
"description ": "",
"type ": "ec2 ",
"arn ": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ",
"ownerArn ": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/1562929437597457834 "
} ,
{ "id ": "cccccccccccccccccccccccccccccccc ",
"name ": "AWS CLI ",
"description ": "",
"type ": "ec2 ",
"arn ": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:cccccccccccccccccccccccccccccccc ",
"ownerArn ": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/botocore-session-1562929475 "
} ] } それぞれの ownerArn
を見てみると Terraform ではナノ秒 タイムスタンプ、AWS CLI では botocore-session-
接頭辞にタイムスタンプが自動的に設定されている。これらの違いを AWS マネジメントコンソールで確認してみる。
まずは「Your environments」を見てみると AWS マネジメントコンソールで作成した Cloud9 environment が表示されている。自分で作成したので Permissions は Owner となっている。作成したはずの「Terraform」や「AWS CLI 」は無い。
AWS Cloud9
「Shared with you」を飛ばして「Account environments」を見てみる。先程は無かった「Terraform」と「AWS CLI 」も表示されている。
AWS Cloud9
ではこの「Terraform」や「AWS CLI 」が使えるのかというのを「Open IDE 」を押して試してみるがアクセス権が無いと言われる。
AWS Cloud9
IDE を開くことができないので「Terraform」と「AWS CLI 」は AWS マネジメントコンソールから共有設定をすることができず、AWS CLI から設定することになる。しかし、AWS CLI のロールはオーナーではない membership への DeleteEnvironmentMembership
権限が無いので後述する「membership の削除」で問題が発生することがある。
フローにしてみると下記のようになる。
AWS Cloud9
自身が Cloud9 environment の Owner であれば AWS CLI から追加した membership を Cloud9 IDE から削除することができるが、最も困るのが Terraform で owner_arn
を未指定で作成してしまった場合。Owner が Terraform で作成した ARN になっているので自身を read-write
で membership を追加したとしても Cloud9 IDE に共有設定が表示されないので membership 操作が一切できない。
membership の追加、更新、削除 Cloud9 environment の ID を調べ方 作成した Cloud9 environment の ID を控え忘れてしまった場合は AWS マネジメントコンソールで「Open IDE 」や「View Details」、「Edit」を開けば URL に ID が含まれているのでそれをコピーしてもいい。
AWS CLI では list-environments
サブコマンドで ID の一覧を表示することができるが、この結果を describe-environments
に渡さないと名前がわからない。
Terminal
aws cloud9 list-environments
Result
{ "environmentIds ": [ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ",
"cccccccccccccccccccccccccccccccc "
] }
一つずつ調べるのは面倒だが list-environments
の結果を --query
オプションで整形して describe-environments --environment-ids
の引数に渡せば名前付きで一覧を取り出すことができる。
Cloud9 environment の数が多い場合は --max-items
で調整する必要がある。
Terminal
aws cloud9 describe-environments \ --environment-ids $( aws cloud9 list-environments --query " environmentIds " --output text ) \ --query " environments[].[id, name] " \ --output text
Result
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa AWS Management Console
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb Terraform
cccccccccccccccccccccccccccccccc AWS CLI
membership を追加する membership の追加には create-environment-membership
サブコマンドを使う。ここでは例として IAM ユーザである alice
を read-only
で追加する。
Cloud9 IDE でターミナルを使う場合は read-write
権限が必要。
Terminal
aws cloud9 create-environment-membership \ --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ --user-arn arn:aws:iam::000000000000:user/alice \ --permissions read-only
Result
{ "membership ": { "permissions ": "read-only ",
"userId ": "YYYYYYYYYYYYYYYYYYYYY ",
"userArn ": "arn:aws:iam::000000000000:user/alice ",
"environmentId ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
} }
describe-environment-memberships
で確認すると alice
が read-only
で追加されていることがわかる。
Terminal
aws cloud9 describe-environment-memberships \ --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Result
{ "memberships ": [ { "permissions ": "read-only ",
"userId ": "YYYYYYYYYYYYYYYYYYYYY ",
"userArn ": "arn:aws:iam::000000000000:user/alice ",
"environmentId ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
} ,
{ "permissions ": "owner ",
"userId ": "XXXXXXXXXXXXXXXXXXXXX:john ",
"userArn ": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john ",
"environmentId ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"lastAccess ": 1562920538.0 } ] }
membership を更新する membership の更新には update-environment-membership
サブコマンドを使う。
ここでは上で追加した alice
の権限を read-only
から read-write
に変更する。
Terminal
aws cloud9 update-environment-membership \ --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ --user-arn arn:aws:iam::000000000000:user/alice \ --permissions read-write
Result
{ "membership ": { "permissions ": "read-write ",
"userId ": "YYYYYYYYYYYYYYYYYYYYY ",
"userArn ": "arn:aws:iam::000000000000:user/alice ",
"environmentId ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
} }
再び describe-environment-memberships
で確認すると alice
の権限が read-write
に変更されていることがわかる。
Terminal
aws cloud9 describe-environment-memberships \ --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Result
{ "memberships ": [ { "permissions ": "read-write ",
"userId ": "YYYYYYYYYYYYYYYYYYYYY ",
"userArn ": "arn:aws:iam::000000000000:user/alice ",
"environmentId ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
} ,
{ "permissions ": "owner ",
"userId ": "XXXXXXXXXXXXXXXXXXXXX:john ",
"userArn ": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john ",
"environmentId ": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ",
"lastAccess ": 1562920538.0 } ] }
membership を削除する membership の削除には delete-environment-membership
サブコマンドを使う。
成功した場合は何も表示されない。
Terminal
aws cloud9 delete-environment-membership \ --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ --user-arn arn:aws:iam::000000000000:user/alice
AccessDeniedException の例
先に説明したように AWS マネジメントコンソールで Cloud9 environment を作成した場合、AWS CLI からの操作には DeleteEnvironmentMembership
権限が無いためエラーになる。
Result
An error occurred (AccessDeniedException) when calling the DeleteEnvironmentMembership operation:
User arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/botocore-session-1562923366
is not authorized to perform: cloud9:DeleteEnvironmentMembership on resource: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Cloud9 と Terraform Terraform v0.12.1
Terraform で Cloud9 を扱う場合は aws_cloud9_environment_ec2
リソースを使用する。現状では Cloud9 に関連するリソースはこれしか無い。
aws _cloud9_environment_ec2 を使うときの注意点Cloud9 envionment の membership の説明に書いたとおり、owner_arn
の指定を忘れると membership の操作ができないばかりか Cloud9 IDE に入ることすらできないので(使い方によるが)指定しておいた方が無難。
aws_cloud9_environment_ec2
に変更を加えた場合、大抵は destroy される。automatic_stop_time_minutes
は modify になりそうだが、これも destroy の対象なので自動シャットダウンの時間を変更したければ Cloud9 IDE から変更する必要がある。
modify になるもの
name
を変更するdescription
を変更するdestroy になるもの
instance_type
を変更するautomatic_stop_time_minutes
を設定(never から 30 など)または変更(30 から 60 など)するowner_arn
を設定または変更するTerraform による Cloud9 environment の作成 name
と instance_type
だけ指定すれば Cloud9 environment を作成することができる。
aws _cloud9.tf
resource "aws_cloud9_environment_ec2" "foo " { // STEP 1 name = "Terraform "
instance_type = "t2.micro "
}
Terminal
terraform apply --target aws_cloud9_environment_ec2.foo
terraform state show aws_cloud9_environment_ec2.foo
owner_arn
にはユーザ名としてタイムスタンプが設定される。
# aws_cloud9_environment_ec2.foo :
resource "aws_cloud9_environment_ec2" "foo " { arn = "arn :aws :cloud9 :ap -northeast -1:000000000000:environment :aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
instance_type = "t2 .micro "
name = "foo "
owner_arn = "arn :aws :sts ::000000000000:assumed -role /OrganizationAccountAccessRole /1562844915108062971"
type = "ec2 "
} STEP 2: owner_arn の指定 先程の TF ファイルを変更して owner_arn
を追記する。Terraform に限らずだが owner の変更は出来ないため同一名の Cloud9 environment を作成する場合は再構築する必要がある。
aws _cloud9.tf
resource "aws_cloud9_environment_ec2" "foo " { // STEP 1 name = "foo "
instance_type = "t2 .micro "
// STEP 2
owner_arn = "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john "
}
Terminal
terraform apply --target aws_cloud9_environment_ec2.foo
terraform state show aws_cloud9_environment_ec2.foo
terraform state show
で確認すると owner_arn
が指定したとおりに設定されているのがわかる。
# aws_cloud9_environment_ec2.foo :
resource "aws_cloud9_environment_ec2" "foo " { arn = "arn :aws :cloud9 :ap -northeast -1:000000000000:environment :bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb "
id = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb "
instance_type = "t2 .micro "
name = "foo "
owner_arn = "arn :aws :sts ::000000000000:assumed -role /OrganizationAccountAccessRole /john "
type = "ec2 "
} STEP 3: automatic_stop_time_minutes を指定する Cloud9 ではインアクティブな状態が続いたときに自動的に EC2 インスタンス を停止させることができる機能が用意されている。aws_cloud9_environment_ec2
リソースでは automatic_stop_time_minutes
という引数(数値型)で指定する。未指定の場合は AWS CLI 同様に never
(停止しない)となる。destroy が発生するので「時間を変更したいけれど Cloud9 environment は壊したくない」という場合は IDE を開いて「AWS Cloud9 > Pereferences > PROJECT SETTINGS > EC2 Instance」で設定を変更する。なお、AWS マネジメントコンソールからは変更できない。
aws _cloud9.tf
resource "aws_cloud9_environment_ec2" "foo " { // STEP 1 name = "foo "
instance_type = "t2 .micro "
// STEP 2
owner_arn = "arn :aws :sts ::000000000000:assumed -role /OrganizationAccountAccessRole /john "
// STEP 3
automatic_stop_time_minutes = 30 }
Terminal
terraform apply --target aws_cloud9_environment_ec2.foo
terraform state show aws_cloud9_environment_ec2.foo
指定した場合は下記のように属性と値が表示される。Q & A に書いておくが設定によっては IDE 上で確認できる値と一致しなくなる。指定しなかった場合は自動的に never
となり automatic_stop_time_minutes
属性は出てこない。
Result
# aws_cloud9_environment_ec2.foo :
resource "aws_cloud9_environment_ec2" "foo " { arn = "arn :aws :cloud9 :ap -northeast -1:000000000000:environment :cccccccccccccccccccccccccccccccc "
automatic_stop_time_minutes = 30
id = "cccccccccccccccccccccccccccccccc "
instance_type = "t2 .nano "
name = "bar "
owner_arn = "arn :aws :sts ::000000000000:assumed -role /OrganizationAccountAccessRole /john "
type = "ec2 "
}
EIP の設定やセキュリティグループのカスタマイズの自動化はできるのか Cloud9 envionment には EIP の設定が無いので自動シャットダウンが行われればパブリック IP アドレスは変わってしまうし、セキュリティグループは自動作成以外の選択肢が無いのでインバウンドルールを追加しないと本来の「踏み台」としては使えない。
しかし、Cloud9 で EC2 インスタンス を作成してもステータスには EC2 インスタンス の詳細情報は含まれていない。これは AWS CLI を使っても同じである。EC2 インスタンス やセキュリティグループは CloudFormation によって作成されているので Name
タグには aws-cloud9-環境名-環境ID
という書式で名前が設定されている。CloudFormation の aws:cloud9:environment
タグにも Cloud9 environment の ID が入っているのでここからリソースを検索することもできるだろう。しかし、CloudFormation のスタックが Terraform の管理外で作成されているので変数呼び出しができない。
EC2 インスタンス の作成を通常通り行い、そちらで Cloud9 IDE のインストールと EIP やセキュリティグループを設定したあとに Cloud9 に SSH タイプで追加すれば…という方法も思いつくが残念ながらいまのところ Terraform には aws_cloud9_environment_ssh
というリソースは存在しない。
従って、Cloud9 で EC2 インスタンス を新規に作成する場合は「踏み台」として使うための設定の自動化は簡単ではないと思われる。
Try & Result Try: owner_arn を指定し忘れたのだが Cloud9 IDE を使いたい AWS CLI で cloud9 create-environment-membership
で使用するユーザを membership に追加すればいい。ただし、Cloud9 IDE に membership の設定が表示されず GUI から membership の編集や削除ができないなどの制限があるので潔く作り直したほうがよい。
Try: automatic_stop_time_minutes に適当な値(たとえば 45 など)を設定するとどうなるか terraform show
では設定した通りの値が入っているが Cloud9 IDE で確認してみると切り上げられてプリセット値に設定されていた。(45 の場合であれば 1 時間)
Try: automatic_stop_time_minutes に明示的に never
を指定するにはどうするのか 数値型なので automatic_stop_time_minutes = 0
と指定すれば never
になる。
まとめ 一般的な「踏み台」として使わずに Cloud9 IDE を SSH ログイン用のスポットとして使う分にはいいと思うが、リモートサーバにログインするための秘密鍵 を配置する必要があるなどいくつかの手間は残る。
個人的にはシェルのキーバインド を多用するので Ctrl + W (1単語前を消す)なんて押そうものならタブが落ちてしまうため Cloud9 IDE 上のターミナルは少々使いにくかったりする。
ただ、フロントの開発をやっているエンジニアさん相手には Proxy Jump の説明をするのも一苦労だったりするので AWS アカウントだけあれば使えるというのは便利なのかもしれない。
他のプロジェクトが Cloud9 をどのように SSH の踏み台として使っているのかは知らないがベストプラク ティス的なものが教えてもらいたいものである。