TL;DR
- AWS Systems Managerを使って、EC2インスタンスにSSH鍵なしでアクセスできるようにしたい
- そのための環境を、Terraformで構築する
- AWS Systems Managerを利用するためには、EC2に
AmazonSSMManagedInstanceCore
ポリシーを含むIAMインスタンスプロファイルを付与する必要がある
AWS Systems Manager
AWS Systems Managerとは、AWSインフラリソースの運用の役立つサービスです。
AWS Systems Managerの機能は、こちら。
また、関連するドキュメントやポリシーなどの名前で「SSM」というのが出てくるのですが、こういう経緯みたいです。
AWS Systems Manager (Systems Manager) は、以前は「 Amazon Simple Systems Manager (SSM) 」や「 Amazon EC2 Systems Manager (SSM) 」と呼ばれていました。サービスの元の省略名「 SSM 」は、他のいくつかのサービスコンソールを含むさまざまな AWS リソースにまだ反映されています。
AWS Systems Managerが利用できるOSは、こちら。
あと、利用のための前提条件も読んでおくとよいでしょう。
Session Manager
Session Managerは、AWS Systems Managerの機能のうちのひとつで、AWS CLIを使ってEC2等の仮想マシンを管理することができるツールです。
AWS Systems Manager Session Manager
Session Managerを使うと、SSHキーを管理することなく、EC2インスタンスにアクセスしたり、管理することができます。
今回は、このSession Managerを使える状態にしたEC2インスタンスを、Terraformで作ることを目標にします。EC2インスタンスは、PublicサブネットおよびPrivateサブネットに配置することにします。
OSに関しては、Amazon Linux 2を使用します。
環境
今回の環境は、こちらになります。
$ terraform version
Terraform v0.12.24
$ aws --version
aws-cli/2.0.12 Python/3.7.3 Linux/4.15.0-99-generic botocore/2.0.0dev16
$ session-manager-plugin --version
1.1.61.0
コード
作成したコードは、こちら。
main.tf
terraform {
required_version = ">= 0.12.24"
}
provider "aws" {
version = "2.61.0"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "2.33.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a"]
public_subnets = ["10.0.101.0/24"]
private_subnets = ["10.0.1.0/24"]
map_public_ip_on_launch = true
enable_nat_gateway = true
single_nat_gateway = true
}
data "aws_iam_policy_document" "assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_role" "role" {
name = "MyRole"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
data "aws_iam_policy" "systems_manager" {
arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_role_policy_attachment" "default" {
role = aws_iam_role.role.name
policy_arn = data.aws_iam_policy.systems_manager.arn
}
resource "aws_iam_instance_profile" "systems_manager" {
name = "MyInstanceProfile"
role = aws_iam_role.role.name
}
resource "aws_instance" "public" {
ami = "ami-0f310fced6141e627"
instance_type = "t2.micro"
iam_instance_profile = aws_iam_instance_profile.systems_manager.name
subnet_id = module.vpc.public_subnets[0]
}
resource "aws_instance" "private" {
ami = "ami-0f310fced6141e627"
instance_type = "t2.micro"
iam_instance_profile = aws_iam_instance_profile.systems_manager.name
subnet_id = module.vpc.private_subnets[0]
}
クレデンシャルは、環境変数で設定することにします。
$ export AWS_ACCESS_KEY_ID=...
$ export AWS_SECRET_ACCESS_KEY=...
$ export AWS_DEFAULT_REGION=ap-northeast-1
VPC、サブネットを定義する
基礎となるネットワーク部分に関しては、AWS VPC Terraform moduleを使ってまるっと定義しました。
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "2.33.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a"]
public_subnets = ["10.0.101.0/24"]
private_subnets = ["10.0.1.0/24"]
map_public_ip_on_launch = true
enable_nat_gateway = true
single_nat_gateway = true
}
これで、以下が組み上がります。
- VPC
- インターネットゲートウェイ
- EIP
- NAT ゲートウェイ
- ルーティングテーブル
- Publicサブネット
-
map_public_ip_on_launch
をtrue
にして、Public IPを付与する
-
- Privateサブネット
IAMインスタンスプロファイルを定義する
続いて、EC2をAWS Systems Managerで利用できるように、EC2にアタッチするIAMインスタンスプロファイルを作成します。
まずは、IAMロールを定義。
data "aws_iam_policy_document" "assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_role" "role" {
name = "MyRole"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
IAMロールにアタッチしているのは、EC2がロールを使えるようにするためのポリシーです。
定義したIAMロールに、AmazonSSMManagedInstanceCore
ポリシーをアタッチします。
data "aws_iam_policy" "systems_manager" {
arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_role_policy_attachment" "default" {
role = aws_iam_role.role.name
policy_arn = data.aws_iam_policy.systems_manager.arn
}
Systems Manager の IAM インスタンスプロファイルを作成する
IAMインスタンスポリシーを定義し、IAMロールを紐付けます。
resource "aws_iam_instance_profile" "systems_manager" {
name = "MyInstanceProfile"
role = aws_iam_role.role.name
}
これで、EC2に付与するIAMインスタンスプロファイルが定義できました。
IAMインスタンスプロファイルって、AWSマネジメントコンソールからIAMロールを作った時には、自動で作られるんですね…。
[IAM role] リストには、IAM ロールの作成時に作成したインスタンスプロファイルの名前が表示されます。コンソールを使用して IAM ロールを作成した場合、インスタンスプロファイルが自動的に作成され、ロールと同じ名前が付けられます。IAM、API、または AWS CLI SDK を使用して AWS を作成した場合、インスタンスプロファイルに異なる名前を付けた可能性があります。
Amazon EC2 インスタンスで実行されるアプリケーションに IAM ロールを使用してアクセス許可を付与する
EC2インスタンスを定義する
あとは、IAMインスタンスプロファイルを紐付けたEC2インスタンスを定義します。
resource "aws_instance" "public" {
ami = "ami-0f310fced6141e627"
instance_type = "t2.micro"
iam_instance_profile = aws_iam_instance_profile.systems_manager.name
subnet_id = module.vpc.public_subnets[0]
}
resource "aws_instance" "private" {
ami = "ami-0f310fced6141e627"
instance_type = "t2.micro"
iam_instance_profile = aws_iam_instance_profile.systems_manager.name
subnet_id = module.vpc.private_subnets[0]
}
参考
- aws_iam_policy
- Data Source: aws_iam_policy_document
- Resource: aws_iam_role
- Resource: aws_iam_role_policy_attachment
- Resource: aws_iam_instance_profile
構築
$ terraform init
$ terraform apply
Session Managerでアクセス
以下のコマンドで、EC2にアクセスできます。
$ aws ssm start-session --target [EC2のインスタンスID]
成功すると、こんなメッセージが表示されて
Starting session with SessionId: xxxxx
シェルが使えるようになります。
sh-4.2$
その他
今回、Publicサブネットで起動するEC2にはPublic IPを付与し、PrivateサブネットではNAT ゲートウェイを使える構成にしてますが、これらをやめるとSession Managerで接続できなくなります。
本来は、VPCエンドポイントを作成してアクセスするのが筋なんでしょうね。