こんにちは、近藤(りょう)です!
"Public" ではなく "Private" な環境で開発を行う場合に VPC など諸々の下準備(主に足回り)が必要でしたので 環境構築の 効率化重視 で「CFn(CloudFormation)を用いて AWS Cloud9 の環境をセットアップ」をしてみました。
AWS Cloud9 について
AWS Cloud9 は、ブラウザのみを使用してコードを記述、実行、デバッグできる無料のクラウドベースの統合開発環境 (IDE) です。IDE には、コードエディタ、デバッガー、ターミナルが含まれています。
AWS Cloud9 には、JavaScript、Python、PHP などの一般的なプログラム言語に不可欠なツールがあらかじめパッケージ化されているため、新しいプロジェクトを開始するためにファイルをインストールしたり、開発マシンを設定したりする必要はありません。
AWS Cloud9(Cloud IDE でコードを記述、実行、デバッグ)| AWS
Private な環境でのAWS Cloud9 利用について
AWS Cloud9 には SSH と SSM(AWS Systems Manager)2つのネットワーク接続方式が提供されていますが、Private な環境(Private Subnet上) に AWS Cloud9 を構築するので "SSM 接続方式" を選択する必要があります。
- 以下、Amazon VPC 要件 AWS Cloud9 の抜粋
- 環境が SSH 経由で EC2 インスタンスに直接アクセスしている場合、インスタンスはパブリックサブネットでのみ起動できます。
- Systems Manager を使って no-ingress Amazon EC2 インスタンスにアクセスしている場合、インスタンスはパブリックサブネットまたはプライベートサブネットに起動できます。
- プライベートサブネットを使用している場合は、パブリックサブネットで NAT ゲートウェイをホストして、サブネットのインスタンスによるインターネットとの通信を許可します。
「パブリックサブネットで NAT ゲートウェイをホストして、サブネットのインスタンスによるインターネットとの通信を許可します。」と記載がありますが
Systems Manager でプライベート EC2 インスタンスを管理できるようにVPCエンドポイントを利用すればできるようですね。
必要なVPCエンドポイント
- com.amazonaws.[region].ec2messages
- com.amazonaws.[region].ssm
- com.amazonaws.[region].ssmmessages
参考
AWS Systems Manager を使用して no-ingress EC2 インスタンスにアクセスする - AWS Cloud9
インターネットにアクセスせずにプライベート EC2 インスタンスを管理する | AWS re:Post
ただ、インターネットにつながっていないとそれはそれで開発効率は落ちそうです。
今回の構成
Private Subnet 上に AWS Cloud9 を配置して NAT Gateway 経由で外部(インターネット)への接続ができるような構成を構築します。
環境構築してみる
東京リージョンにAWS Cloud9を構築してみます。
CFn 実行
東京リージョンでCFnをぽちっとな。
※Parametersは各々修正お願いします。
AWSTemplateFormatVersion: '2010-09-09' Description: Create a VPC with Public/Private Subnets, NAT Gateway, and Cloud9 IDE on Private Subnet using Session Manager Parameters: EnvironmentName: Description: An environment name that is prefixed to resource names Type: String Default: myapp VpcCIDR: Description: Please enter the IP range (CIDR notation) for this VPC Type: String Default: 10.200.0.0/16 AvailabilityZoneName: Description: Please enter the AvailabilityZoneName for Availability Zone Type: String Default: ap-northeast-1a PublicSubnetCIDR: Description: Please enter the IP range (CIDR notation) for the public subnet Type: String Default: 10.200.0.0/24 PrivateSubnetCIDR: Description: Please enter the IP range (CIDR notation) for the private subnet Type: String Default: 10.200.1.0/24 Cloud9OwnerArn: Type: String Default: <Cloud9 OWNER ARN> # Cloud9OwnerArnの部分はCloud9環境のオーナーにしたいIAMユーザー、ロールのARNを記載 # 別アカウントからスイッチロールした先のアカウントでCloud9を構築する場合はarn:aws:sts::スイッチ先アカウント番号:assumed-role/スイッチ先ロール名/セッション名(ユーザー名) Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Basic Configuration" Parameters: - "EnvironmentName" - "VpcCIDR" - "AvailabilityZoneName" - "PublicSubnetCIDR" - "PrivateSubnetCIDR" - "Cloud9OwnerArn" Resources: # ------------------------------------------------------------# # VPC # ------------------------------------------------------------# VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsHostnames: true EnableDnsSupport: true InstanceTenancy: default Tags: - Key: Name Value: !Sub ${EnvironmentName}-vpc # ------------------------------------------------------------# # PublicSubnet # ------------------------------------------------------------# PublicSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Ref AvailabilityZoneName CidrBlock: !Ref PublicSubnetCIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${EnvironmentName}-public-subnet # ------------------------------------------------------------# # PrivateSubnet # ------------------------------------------------------------# PrivateSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Ref AvailabilityZoneName CidrBlock: !Ref PrivateSubnetCIDR MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Sub ${EnvironmentName}-private-subnet # ------------------------------------------------------------# # InternetGateway and associate # ------------------------------------------------------------# InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub ${EnvironmentName}-igw InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway # ------------------------------------------------------------# # Nat Gateway # ------------------------------------------------------------# NatGateway: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGatewayEIP.AllocationId SubnetId: !Ref PublicSubnet Tags: - Key: Name Value: !Sub ${EnvironmentName}-ngw NatGatewayEIP: Type: AWS::EC2::EIP Properties: Domain: vpc # ------------------------------------------------------------# # PublicSubnet Route Table # ------------------------------------------------------------# PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-public-route DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway # ------------------------------------------------------------# # PrivateSubnet Route Table # ------------------------------------------------------------# PrivateRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvironmentName}-private-route DefaultPrivateRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway # ------------------------------------------------------------# # PublicSubnet Associate # ------------------------------------------------------------# PublicSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet # ------------------------------------------------------------# # PrivateSubnet Associate # ------------------------------------------------------------# PrivateSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable SubnetId: !Ref PrivateSubnet # ------------------------------------------------------------# # Cloud9 # ------------------------------------------------------------# Cloud9Environment: Type: AWS::Cloud9::EnvironmentEC2 Properties: InstanceType: t2.micro SubnetId: !Ref PrivateSubnet AutomaticStopTimeMinutes: 30 ImageId: resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2023-x86_64 Name: !Sub ${EnvironmentName}-cloud9 ConnectionType: CONNECT_SSM OwnerArn: !Ref Cloud9OwnerArn Outputs: Cloud9EnvironmentId: Description: The ID of the Cloud9 Environment Value: !Ref Cloud9Environment VPCId: Description: The ID of the VPC Value: !Ref VPC PublicSubnetId: Description: The ID of the Public Subnet Value: !Ref PublicSubnet PublicSubnetCIDR: Description: The CIDR of the Public Subnet Value: !Ref PublicSubnetCIDR PrivateSubnetId: Description: The ID of the Private Subnet Value: !Ref PrivateSubnet PrivateSubnetCIDR: Description: The CIDR of the Private Subnet Value: !Ref PrivateSubnetCIDR NATGatewayId: Description: The ID of the NAT Gateway Value: !Ref NatGateway NATGatewayEIP: Description: The Elastic IP of the NAT Gateway Value: !Ref NatGatewayEIP Cloud9EnvironmentName: Description: The Name of the Cloud9 Environment Value: !GetAtt Cloud9Environment.Name
AWS Cloud9 の CFnの記載は「AWS::Cloud9::EnvironmentEC2」をご参照ください。
CFn 状態確認
CFnで作成するとマネージメントコンソールで AWS Cloud9 を作成した時と同じように AWS Cloud9用のCFn が動くみたいです。
ネットワーク 状態確認
CFnで作成した AWS Cloud9 のサブネットを確認します。
PrivateSubnet上に起動しているのが確認できます。(サブネット IDで検索)
リソースマップも確認してみる。(NATGW経由になっている)
AWS Cloud9 接続
AWS Cloud9を開いてみましょう。
対象の環境の「開く」を押下する。
AWS Cloud9へ接続できました。
※すぐ立ち上がらないこともありますのでその時はブラウザを更新してください
これでPrivate な環境でAWS Cloud9を作成することができました。
AWS Cloud9からNatGW経由でインターネットへ通信することもできます。
まとめ
Private な環境で開発をする必要があるといった場合に VPC などを手動で作成しておくのは手間がかかるのでCFnを利用した環境作成をご紹介させていただきました。
あまり、必要になることはないかもしれませんがどなたかの支えになれば幸いです。