目次
はじめに
CloudFormationでセッションマネージャ接続可能な検証用EC2を構築したい!ってことで第2弾です。
第1弾のNatGatewayを使用したCloudFormationテンプレートはこちらになります。
1度作成したリソースをそのまま残しておけば検証は楽ですが、思わぬとこでコストがかかってしまったり、多額の請求につながってしまう恐れがあります。
簡単な検証をするためにいちいちサブネット作って、SGを設定して、エンドポイント作成したけど、セッションマネージャでうまく繋がらなかった時ってめちゃくちゃストレスですよね。。。
どこの設定を間違えているかか探す時間がもったいないし
ということでセッションマネージャーで接続可能な検証用EC2を手軽に構築できるCloudFormationテンプレートを作成しました。
セッションマネージャーとは
めっっっっっちゃくちゃ簡単にまとめるとSSH鍵を使用せず、EC2に接続できるサービスです。
プライベートサブネットに配置したEC2に接続しようとした場合、パブリックIPアドレスが振られていないので直接SSHで接続することができず、パブリックサブネットに配置した踏み台サーバ等からSSHで接続する必要があります。
セッションマネージャーを使用するとAWSコンソール画面からプライベートサブネット内のEC2に直接接続でき、踏み台サーバやSSH鍵が不要になります。
構築概要図
今回CloudFormationでテンプレート化したVPCエンドポイントを使用した構成の概要図です。
(図には記載がないですが、SGで疎通を制限したり、IAMロールもアタッチします)
第1弾でもご紹介しましたがセッションマネージャーを使用したEC2への接続方法はいくつか方法があります。
前回はNATGatewayを使用したCloudFormationテンプレートを紹介しましたが、今回はVPCエンドポイントを使用した接続です。
VPCエンドポイントとは
まず初めにVPCエンドポイントって何?って方に向けて簡単にですが説明します。
VPCエンドポイントを使用するとVPC内のサービスとVPC外のAWSサービスをインターネットを経由せずに(プライベートに)接続することができます。
具体例だとEC2とS3間をインターネットを経由せずに接続することが可能になります。
エンドポイントには「ゲートウェイエンドポイント」、「インターフェースエンドポイント」、「GatewayLoadBalancerエンドポイント」の3種類があり、今回使用するは「インターフェースエンドポイント」と「ゲートウェイエンドポイント」になります。
それぞれのエンドポイントの違いについて説明するとそれだけでいくつか記事が書けそうなので割愛させていただきますが、よくわからない方はとりあえず、AWSリソース同士をプライベートに接続するために機能なんだなぁってくらいで考えておいてください。
インターフェースエンドポイント同士は接続可能だったり、ゲートウェイエンドポイント同士は接続不可(名前解決できず、ルートテーブルを使用した接続しかできないため)とか詳しく書き出すとすさまじい量になりそうなので。。。
スタックの作成
前置きが長くなってしまいましたが本題のテンプレートです。
各パラメータの説明とかどうやってここまで書き上げたかって話を書いちゃうと
めちゃくちゃ長くて読む気が失せると思うので今回は割愛します。
近いうちに別の記事で紹介できたらなと思ってますので、もしよかったら読んでください。
AWSTemplateFormatVersion: 2010-09-09
Parameters:
VPCName:
Type: String
Default: SesssionManagerVPCEndpoint
VPCCidrBlock:
Type: String
Default: 10.0.0.0/16
PrivateSubnetCidrBlock:
Type: String
Default: 10.0.1.0/24
AZ1:
Type: String
AllowedValues:
- ap-northeast-1a
- ap-northeast-1c
- ap-northeast-1d
CustomAMI:
Type: String
#インスタンスに使用するAMIを指定
Default: ami-*****************
AllowedValues:
- ami-*****************
- ami-*****************
- ami-*****************
InstanceType:
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t3.micro
- t3.small
- m1.small
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidrBlock
EnableDnsHostnames: 'True'
Tags:
- Key: Name
Value: !Ref VPCName
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AZ1
VpcId: !Ref VPC
CidrBlock: !Ref PrivateSubnetCidrBlock
MapPublicIpOnLaunch: 'false'
Tags:
- Key: Name
Value: SessionManagerPrvSub
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: PrivateRouteTable
PriAssociateRouteTable:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VPC
GroupDescription: SecurityGroup-for-EC2-SessionManager
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 443
ToPort: 443
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 25
ToPort: 25
Tags:
- Key: Name
Value: EC2ssessionmanagerSG
VPCEndpointSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VPC
GroupDescription: SecurityGroup-for-VPCEndpoint
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref EC2SecurityGroup
IpProtocol: tcp
FromPort: 443
ToPort: 443
Tags:
- Key: Name
Value: VPCEndpoint-SG
EndpointSSM:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref VPCEndpointSecurityGroup
ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
SubnetIds:
- !Ref PrivateSubnet
VpcEndpointType: Interface
VpcId: !Ref VPC
EndpointSSMMessages:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref VPCEndpointSecurityGroup
ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
SubnetIds:
- !Ref PrivateSubnet
VpcEndpointType: Interface
VpcId: !Ref VPC
EndpointEC2Messages:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref VPCEndpointSecurityGroup
ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
SubnetIds:
- !Ref PrivateSubnet
VpcEndpointType: Interface
VpcId: !Ref VPC
EndpointS3:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- !Ref PrivateRouteTable
ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
VpcEndpointType: Gateway
VpcId: !Ref VPC
InstanceProfile:
DependsOn: SessionManagerRole
Type: AWS::IAM::InstanceProfile
Properties:
Path: '/'
Roles:
- !Ref SessionManagerRole
SessionManagerRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'ec2.amazonaws.com'
Action:
- 'sts:AssumeRole'
Path: '/'
RoleName: vpcendpoint-SessionManager-role-cfn
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
myEC2Instance:
Type: AWS::EC2::Instance
DependsOn: PrivateSubnet
Properties:
ImageId: !Ref CustomAMI
InstanceType: !Ref InstanceType
SubnetId: !Ref PrivateSubnet
IamInstanceProfile: !Ref InstanceProfile
SecurityGroupIds:
- !Ref EC2SecurityGroup
Tags:
- Key: Name
Value: Cfn-sessionmanager-instance
スタックの起動方法につきましては、「【AWS】CloudFormationでセッションマネージャで接続可能なEC2を構築してみた(NATGateway編)」で紹介していますのでわからない方はこちらを参考にしてください。(よかったら拡散も!)
https://qiita.com/itkz1016/items/1c39f024a00b020c5bd7
稼働確認
テンプレートからスタックを作成したら作成完了まで待ちます。
スタック名に指定した論理IDのステータスが「CREATE_COMPLETE」になれば成功です。
今回は「VPCEndopoint-SessionManager」というスタック名で作成しています。
VPCを確認すると指定したCIDRで作成されていることが確認できました。
VPCEndpointを確認してみます。
今回Nameタグの指定をしなかったので名前タグいていませんが4つ作成されていることが確認できます。
この4種(もしくはcom.amazonaws.ap-northeast-1.s3以外の3つ)はEC2とセッションマネージャを行う際に必要なエンドポイントとなります。
各エンドポイントの詳細は以下の公式ドキュメントをご参照ください。
https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-create-vpc.html#sysman-setting-up-vpc-create
次にエンドポイント用とEC2用にそれぞれ作成したセキュリティグループを見てみましょう。
まずはエンドポイント用セキュリティグループです。
EC2にアタッチしたSGを送信元ソースに指定し、HTTPS:443のインバウンドを許可しています。
次にEC2用セキュリティグループです。
VPCエンドポイントにアタッチしたセキュリティグループを送信先ソースとして指定し、HTTPS:443のアウトバウンドを許可しています。
大まかな設定を確認したので、いよいよ接続していきます。
EC2のコンソール画面で接続したいインスタンスを選択し、「接続」を押下します。
セッションマネージャの接続が可能な状態になって入れば「接続」の文字がオレンジになります。
接続完了
よくある設定ミス
AWSの勉強を始めたばかりのころに自分も経験したのですが、セッションマネージャーで接続するためにはVPCにサブネットを作成し、EC2を起動するだけでは接続できません。
セッションマネージャーで接続できない場合によくある設定ミスをいくつか挙げておきます。
- 接続先EC2にアタッチしたロールに「AmazonSSMManagedInstanceCore」ポリシーがアタッチされていない
- 接続対象インスタンスにSSmエージェントがインストールされていない
- SGのアウトバウンド:443が許可されていない(SSMエージェントが使用するポート)
- NACLでインバウンド・アウトバウンドが許可されていない、もしくは拒否されている
(NACLはステートレスなのでインバウンド・アウトバウンドで明示的な許可が必要です)- VPCエンドポイントが足りない
さいごに
セッションマネージャー第2弾ということで書いてみましたが、NatGatewayを使用する構成よりは、VPCエンドポイントのほうが少し安いのかな?ってことでよく使ってます。(エンドポイントが大量に必要な場合はコスト面ではNatGatewayの使用をお勧めします。)
ただ、手作業で設定しようとするとVPCエンドポイントへのルートテーブルの設定だったり、エンドポイントとEC2それぞれに作成するセキュリティグループの設定が必要でちょっとだけ大変な気がします。
今回載せたテンプレートの解説はあえて割愛したのでCloudFormationのことがよくわからない方はなぜ動いているのか疑問に思っているかと思います。テンプレートを書く際のコツとか、何を考えて、何を見ながら書いているのかって話もどこかのタイミングで記事にできたらなと思います。
もしよかったらTwitterでの拡散もお願いします!