AWS Cloud9をCloudFormationで作成する事によって出来る事、マネジメントコンソールとの挙動の違い
CloudFormationでCloud9を作成してみる
DevelopersIO BASECAMP参加者の加藤です。
本記事ではCloudFormationでCloud9の統合開発環境(IDE)を作成して、挙動を確認してみたいと思います!
CLoud9の概要
Cloud9の概要についてはこちらを参照ください。
マネジメントコンソールで作成する場合
以下が2023年6月5日現在、コンソールから作成する際に選択可能な項目です。
まずはこれをテンプレートで再現してみたいと思います。
CloudFormationで再現
テンプレート
以下がテンプレートになります。
一点、先ほどのマネジメントコンソールでは、既存のサブネットを指定可能(指定しない場合はデフォルトVPCに存在するサブネット中から自動選択。)でしたが、指定有無の分岐をConditionsで表現するのは少々やりすぎかと思いますので、ここでは無指定としました。
その他コメントアウトしているプロパティについては、後ほど触れたいと思います。
AWSTemplateFormatVersion: "2010-09-09"
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Cloud9
Parameters:
- AutomaticStopTimeMinutes
- ConnectionType
- Description
- ImageId
- InstanceType
- Name
Parameters:
AutomaticStopTimeMinutes:
Type: Number
MinValue: 0
MaxValue: 20160
Default: 30
ConnectionType:
Type: String
AllowedValues: [CONNECT_SSM, CONNECT_SSH]
Default: CONNECT_SSM
Description:
Type: String
ImageId:
Type: String
AllowedValues: [amazonlinux-1-x86_64, amazonlinux-2-x86_64, ubuntu-18.04-x86_64]
Default: amazonlinux-2-x86_64
InstanceType:
Type: String
AllowedPattern: ^[a-z][1-9][.][a-z0-9]+$
Default: t2.micro
Name:
Type: String
Resources:
Cloud9:
Type: AWS::Cloud9::EnvironmentEC2
Properties:
AutomaticStopTimeMinutes: !Ref AutomaticStopTimeMinutes
ConnectionType: !Ref ConnectionType
Description: !Ref Description
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
Name: !Ref Name
# OwnerArn: !Sub arn:aws:iam::${AWS::AccountId}:user/${[IAMユーザーの論理ID]} # 環境所有者を別に指定したい場合に利用
# Repositories: # CodeCommitリポジトリをクローンする場合指定
# - PathComponent: string # 必須: はい AWS CodeCommit リポジトリのクローンを作成する、開発環境のデフォルトのファイル システムの場所内のパス。
# RepositoryUrl: string # 必須: はい クローンを作成する AWS CodeCommit リポジトリのクローン URL。
# SubnetId: !Ref [サブネットの論理ID]
# Tags: # Keyに”Name”は指定不可。
# - Key: string
# Value: string
Outputs:
Cloud9Arn:
Value: !GetAtt Cloud9.Arn
パラメータについて
デフォルト値は現在のマネジメントコンソールでの初期値と一致させてあります。
NameとDescriptionだけ指定して実行ください。
スタック実行時の挙動
今回は「test1」というスタック名とNameを指定して実行しました。
test1スタックを実行すると、同スタックの作成が「CREATE_COMPLETE」になる前に以下のように「aws-cloud9-test1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx」スタックが出現し、「CREATE_COMPLETE」になり、それを受けて、test1スタックが「CREATE_COMPLETE」となりました。
「aws-cloud9-test1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx」スタック内のリソースは
・EC2インスタンス
・セキュリティグループ
となり、マネジメントコンソールでCloud9を立てた時と同じスタックである事が確認出来ます。
セキュリティグループのインバウンドルール、アウトバウンドルールはデフォルト、
テンプレートにインスタンスプロファイル等を指定する項目はありませんが、通常通り"AWSCloud9SSMInstanceProfile"が指定されています。
挙動としては一見、AWS::Serverless transformを利用した場合に似ていますが、スタックはネストされておらず、下図のような動きになっている事がわかります。
この事から、マネジメントコーンソールから環境を削除したり、「aws-cloud9-test1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx」スタックを削除したりすると、「test1」スタックは残る(実態のリソースは削除された状態)事が確認出来ました。
注意点があるとすると、transformを使った場合と違い、マネジメントコンソール上でスタック同士に事実上の親子関係がある事が一見してわからない事かと思います。
CloudFormationでは「amazonlinux-1-x86_64」を指定する事も可能
現状マネジメントコンソールでは、以下2種類が選択可能となっており、意図してUbuntsを選択した場合を除き、「Amazon Linux 2」=「Amazon Linux 2:amazonlinux-2-x86_64」を選択した事となります。(AMIを比較して確認済み)
一方CloudFormationではユーザーガイド上、無指定の場合「Amazon Linux (デフォルト):amazonlinux-1-x86_64」の挙動となっているようです。(※記事作成時点)
(「AMIの場所」に”Default”の文字)
コメントアウトしていた部分
「Tags:」
Tagsプロパティですが、いつもであれば確認の為にNameタグを指定する所ですが、Cloud9リソース作成にあたっては、以下エラーが起きる事が確認出来ました。
Tag cannot have the key 'Name' as it is a reserved key by EC2.
「OwnerArn:」
この値を明示的に指定した場合、指定のユーザーが所有権を持ったCloud9が作成されます。
つまり、指定の値がスタック作成ユーザーを指す値でなかった場合は、スタック作成者のCloud9コンソールにはCloud9リソースは表示されません。
今回のテンプレートでは、${AWS::AccountId}を利用していますので、作成されたEC2インスタンスなどは閲覧出来るようになっていますが、何らかスタック作成者に権限を付与する必要はあるかと思いますが、パラメーター値に別のアカウントIDを指定する事で別アカウントにも作成する事が出来るのではと思います。
以下お試し用のテンプレートになります。
AWSTemplateFormatVersion: "2010-09-09"
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Cloud9
Parameters:
- AutomaticStopTimeMinutes
- ConnectionType
- Description
- ImageId
- InstanceType
- Name
- Label:
default: IAMUser
Parameters:
- IAMUserName
- IAMUserLoginPassword
Parameters:
AutomaticStopTimeMinutes:
Type: Number
MinValue: 0
MaxValue: 20160
Default: 30
ConnectionType:
Type: String
AllowedValues: [CONNECT_SSM, CONNECT_SSH]
Default: CONNECT_SSM
Description:
Type: String
ImageId:
Type: String
AllowedValues: [amazonlinux-1-x86_64, amazonlinux-2-x86_64, ubuntu-18.04-x86_64]
Default: amazonlinux-2-x86_64
InstanceType:
Type: String
AllowedPattern: ^[a-z][1-9][.][a-z0-9]+$
Default: t2.micro
Name:
Type: String
IAMUserName:
Type: String
IAMUserLoginPassword:
Type: String
NoEcho: true
Resources:
Cloud9:
Type: AWS::Cloud9::EnvironmentEC2
Properties:
AutomaticStopTimeMinutes: !Ref AutomaticStopTimeMinutes
ConnectionType: !Ref ConnectionType
Description: !Ref Description
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
Name: !Ref Name
OwnerArn: !Sub arn:aws:iam::${AWS::AccountId}:user/${User}
User:
Type: AWS::IAM::User
Properties:
UserName: !Ref IAMUserName
LoginProfile:
Password: !Ref IAMUserLoginPassword
PasswordResetRequired: false
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
Outputs:
Cloud9Arn:
Value: !GetAtt Cloud9.Arn
上記テンプレートでは「DeletionPolicy:に Retain」を指定していませんので、スタック削除するとユーザーも一緒に消えます。
Cloud9の環境の所有者が指定のIAMユーザーであっても、所有者以外がスタック削除による環境削除を不可にするものではなさそうです。
ちなみに、公式が出しているテンプレートから
OwnerArn: !Sub arn:${AWS::Partition}:sts::${AWS::AccountId}:assumed-role/TeamRole/MasterKey
のようにユーザー以外(プリンシパルタイプに「Role sessions」を選択して作成されたロールのARN)を指定している例もありました。
「SubnetId:」
当記事ではテンプレート例は作成していませんが、パラメーターでSubnetIdを渡すか、スタック内で作成して!Refとするかでサブネットを指定可能です。
「Repositories:」
最後に「Repositories:」ですが、ユーザーガイドには、
↓
とあります。
以下お試し用のテンプレートとなります。
「PathComponent」パラメーター値は"/REPOSITORY_NAME"としていますが、変更いただいて問題ありません。
AWSTemplateFormatVersion: "2010-09-09"
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Cloud9
Parameters:
- AutomaticStopTimeMinutes
- ConnectionType
- Description
- ImageId
- InstanceType
- Name
- PathComponent
- Label:
default: CodeCommit
Parameters:
- CodeCommitRepositoryName
Parameters:
AutomaticStopTimeMinutes:
Type: Number
MinValue: 0
MaxValue: 20160
Default: 30
ConnectionType:
Type: String
AllowedValues: [CONNECT_SSM, CONNECT_SSH]
Default: CONNECT_SSM
Description:
Type: String
ImageId:
Type: String
AllowedValues: [amazonlinux-1-x86_64, amazonlinux-2-x86_64, ubuntu-18.04-x86_64]
Default: amazonlinux-2-x86_64
InstanceType:
Type: String
AllowedPattern: ^[a-z][1-9][.][a-z0-9]+$
Default: t2.micro
Name:
Type: String
PathComponent:
Type: String
Default: /REPOSITORY_NAME
CodeCommitRepositoryName:
Type: String
Resources:
Cloud9:
Type: AWS::Cloud9::EnvironmentEC2
Properties:
AutomaticStopTimeMinutes: !Ref AutomaticStopTimeMinutes
ConnectionType: !Ref ConnectionType
Description: !Ref Description
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
Name: !Ref Name
Repositories:
- PathComponent: !Ref PathComponent
RepositoryUrl: !GetAtt Repository.CloneUrlHttp
Repository:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryName: !Ref CodeCommitRepositoryName
Outputs:
Cloud9Arn:
Value: !GetAtt Cloud9.Arn
(当該プロパティを指定しなかった場合)
(当該プロパティを指定した場合)
「warning: You appear to have cloned an empty repository.」の表示が出てしまいましたが、起動時上記のようにbashが走る事まで確認する事が出来ました。
出来なさそうだった事
CloudFormationで作成したからといって、test1スタックでCloud9と合わせてIAMロールを作成しても、RoleのArnなど渡すプロパティが見当たらない為「aws-cloud9-test1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx」が作成したEC2インスタンスに予めロールをアタッチして作成させる事は出来なさそうでした。
(マネジメントコンソールでも然り)
また、AWS managed temporary credentialsの有効化/無効化を指定するプロパティもありませんでした。
参考:AMTCについての技術記事
終わりに
細かい部分で色々と勉強になった所もあり、触ってみる前よりもCloud9の事を少し深ぼって知る事が出来た気がします。
どなたかの知識や理解のお役に立てている部分があれば幸いです。
お読みいただき有難うございました!
Discussion