SSMセッションマネージャーでコンソールアクセスできるEC2をCloudFormationで自動作成する方法
こんにちは、Masuyama です。
突然ですが SSM の機能の一つであるセッションマネージャーのことをご存知でしょうか。
簡単にいうとブラウザ経由でコンソールにアクセスできる機能のことで、公式ドキュメントでは次のように説明されています。
Session Manager はフルマネージド型 AWS Systems Manager 機能であり、インタラクティブなワンクリックブラウザベースのシェルや AWS Command Line Interface (AWS CLI) を介して Amazon Elastic Compute Cloud (Amazon EC2) インスタンス、オンプレミスインスタンス、および仮想マシン (VM) を管理できます。Session Manager を使用すると、インバウンドポートを開いたり、踏み台ホストを維持したり、SSH キーを管理したりすることなく、監査可能なインスタンスを安全に管理できます。
ここに書いてある通り、SSH ポートを開いたりする必要もなく、鍵すら必要ないためセキュアにインスタンスを運用することができます。
ただし、実は特定の IAM マネージドポリシーを付与しなければいけなかったり、インスタンスがインターネットに出られる必要があったりと、地味に落とし穴が多かったりします。
今回はタイトルの通りですが、CloudFormation でパブリックサブネット内に EC2 インスタンスを 1 台立ち上げると同時に SSM セッションマネージャーでアクセスするために必要なポリシーを付与する構成を自動で作れるようにしたいと思います。
テンプレートファイルの完成形
あえて先にテンプレートファイルの完成形を載せて、その中でポイントをピックアップしていきたいと思います。
なお、本当にセッションマネージャーでしかアクセスしないならばインバウンドのポートは究極完全封鎖でもいけるのですが、実用性を考慮して HTTP 80 と SSH 25 ぐらいは開けておきます。
ただし、アクセス元のグローバル IP アドレスぐらいは任意で絞れるようにもしておきます。
AWSTemplateFormatVersion: "2010-09-09"
Description: Provision EC2
Parameters:
EnvironmentName:
Description: Name which you can specify the environment by this name
Type: String
Default: test-environment
VpcCIDR:
Type: String
Default: 10.0.0.0/16
PublicSubnetCIDR:
Type: String
Default: 10.0.0.0/24
KeyName:
Description: The EC2 Key Pair to allow SSH access to the instance
Type: "AWS::EC2::KeyPair::KeyName"
MyIP:
Description: IP address range which is allowed to access this ECS from it
Type: String
Default: 0.0.0.0/0
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-VPC
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-InternetGateway
# InternetGateway をVPCにアタッチ
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCIDR
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PublicSubnet
PublicSubnetRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PublicSubnetRouteTable
# PublicSubnet-インターネット間のルーティング
PublicSubnetToInternet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicSubnetRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
# ルートテーブルをサブネットに関連付け
AssoPublicSubnetRouteTable:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicSubnetRouteTable
EC2:
Type: AWS::EC2::Instance
Properties:
# Amazon Linux 2
ImageId: ami-00d101850e971728d
KeyName: !Ref KeyName
InstanceType: t2.micro
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
SubnetId: !Ref PublicSubnet
GroupSet:
- !Ref EC2SecurityGroup
# EC2作成時にインスタンスプロファイルを指定
IamInstanceProfile:
Ref: SessionManagerIamInstanceProfile
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-EC2
SsmSessionManagerIamRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'ec2.amazonaws.com'
Action:
- 'sts:AssumeRole'
Path: '/'
RoleName: 'SsmSessionManagerIamRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
SessionManagerIamInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
Path: '/'
Roles:
- !Ref SsmSessionManagerIamRole
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: ec2-sg-cf
GroupDescription: Allow SSH and HTTP access only MyIP
VpcId: !Ref VPC
SecurityGroupIngress:
# http
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Ref MyIP
# ssh
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref MyIP
ポイントの抜粋
さて、いくつか注意点とセッションマネージャーに関するところだけ抜粋して紹介していきたいと思います。
指定しているパラメータ
Parameters を使用して、スタック作成時にいくつか入力を求めるようにしています。
...
Parameters:
EnvironmentName:
Description: Name which you can specify the environment by this name
Type: String
Default: test-environment
VpcCIDR:
Type: String
Default: 10.0.0.0/16
PublicSubnetCIDR:
Type: String
Default: 10.0.0.0/24
KeyName:
Description: The EC2 Key Pair to allow SSH access to the instance
Type: "AWS::EC2::KeyPair::KeyName"
MyIP:
Description: IP address range which is allowed to access this ECS from it
Type: String
Default: 0.0.0.0/0
...
名前や説明文から想像出来る通りですが、以下のように定義しています。
- EnvironmentName
- 作る環境を一意に指定するための文字列
- リソースの Name タグの冒頭に付加されます
- VpcCIDR
- CloudFormation で作られる VPC の CIDR
- PublicSubnetCIDR
- CloudFormation で作られるパブリックサブネットの CIDR
- KeyName
- EC2 に用いるキーペア
- アカウントに作成されているキーペアを選択させます
- MyIP
- EC2 へのアクセスを許可するグローバル IP アドレス
セッションマネージャー用の権限付与
SSM セッションマネージャーを使うためには、EC2 インスタンスが AmazonSSMManagedInstanceCore というマネージドポリシー(最初から作成されているポリシー)を与えられている必要があります。
ここでは上記ポリシーを付与した IAM ロールを作成しています。
...
SsmSessionManagerIamRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'ec2.amazonaws.com'
Action:
- 'sts:AssumeRole'
Path: '/'
RoleName: 'SsmSessionManagerIamRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
...
また、インスタンスプロファイルとそのロールを紐付けて、EC2 にインスタンスプロファイルを渡すことで結果的に EC2 インスタンスへ該当のポリシーに与えていることもポイントです。
...
SessionManagerIamInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
Path: '/'
Roles:
- !Ref SsmSessionManagerIamRole
...
EC2:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-00d101850e971728d
KeyName: !Ref KeyName
InstanceType: t2.micro
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
SubnetId: !Ref PublicSubnet
GroupSet:
- !Ref EC2SecurityGroup
# EC2作成時にインスタンスプロファイルを指定
IamInstanceProfile:
Ref: SessionManagerIamInstanceProfile
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-EC2
スタックの作成
これを使って実際に作成していきます。
入力しているパラメータは一例です。
しばらく待つとスタックの作成が完了しますので、SSM サービス画面からセッションマネージャーを使って EC2 のコンソールにアクセスしてみましょう。
先ほど CloudFormation で作成した EC2 を指定して [セッションの開始] を選択します。
必要な IAM ポリシーを与えられているので、問題なくアクセスすることができました。
インターネットに出られる環境なのでもちろん Ping も外部に通ります。
まとめ
CloudFormation で作成する EC2 へセッションマネージャーでアクセス出来るようにすることが目的でしたが、同時に CloudFormation で EC2 に IAM ロール/ポリシーを付与する方法も理解いただけたかと思います。
インスタンスプロファイルで権限を渡すにあたりテンプレートファイルでの書き方に少し特徴があるので、基本的な使い方として身につけておくと便利です。
Discussion