はじめに
この記事では AWS Cloud Tech を通して Cloud Formation を学習して実践していく記事です。
主な内容としては実践したときのメモを中心に書きます。(忘れやすいことなど)
誤りなどがあれば書き直していく予定です。
前回までのおさらい
前回は VPC を構築してプライベートサブネットとパブリックサブネットに
ネットワークを切るところまでやりました。
【AWS】用語を整理しながら学ぶ AWS - part5 Cloud Formation - 3
今回やること
前回構築した VPC 上に EC2 を建てる。
今回はキーペアを利用することとし、AMI の ID はハードコーディングする。
EC2 構築後、コラム的な話題として
いかにして認証情報をコードに載せないかについて調べた内容を共有します。
ちなみに今回は EC2 を建てるだけでかなりつまずいたのでその時のことも共有します。
※サブネット用のコードや VPC 用のコードを書きなおすハメになった。
ファイル名 | 用途 |
---|---|
vpc_network.yml | VPC の構成を管理 |
public_network.yml | パブリックサブネットの構成を管理 |
private_network.yml | プライベートサブネットの構成を管理 |
public_ec2.yml | パブリックサブネット内の EC2 |
private_ec2.yml | プライベートサブネット内の EC2 |
ということで
まず、VPC ネットワークを定義する。
AWSTemplateFormatVersion: 2010-09-09
Resources:
MainVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/21
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: MainVpcfromCF
IGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: igw
Value: igw-cf
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MainVpc
InternetGatewayId: !Ref IGW
Outputs:
MainVpc:
Value: !Ref MainVpc
Export:
Name: MainVpcId
MainIgw:
Value: !Ref IGW
Export:
Name: MainIGWId
パブリックサブネットを定義する。
コンソールでパブリックサブネットを構築する手順を思い出していただけると
手順の中に
インターネットゲートウェイの作成
ルートテーブルの作成
ルートテーブルをサブネットにアタッチ(サブネットに関連付け)
ルートテーブルの設定
上記のような手順があったかと思います。
AWSTemplateFormatVersion: 2010-09-09
Resources:
subnetName:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
VpcId: !ImportValue MainVpcId
CidrBlock: 10.0.2.0/24
Tags:
- Key: Name
Value: PublicSubnet
PubRT:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !ImportValue MainVpcId
Tags:
- Key: PublicRoute
Value: PublicRouteCf
PubToInternet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PubRT
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !ImportValue MainIGWId
routeTableAssocName:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref subnetName
RouteTableId: !Ref PubRT
secGroupName:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: PublicSecGrp
GroupDescription: PublicSecGrp
VpcId: !ImportValue MainVpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: MainVpc
Outputs:
PublicSubnet:
Value: !Ref subnetName
Export:
Name: PublicSubnet
PublicSecGrp:
Value: !GetAtt secGroupName.GroupId
Export:
Name: PublicSecGrp
続いてプライベートサブネットを定義する。
ポイントとしては
パブリックサブネットのIPアドレスからのみ
SSH接続を許可すること
また、インターネットゲートウェイはアタッチしないこと
※もしかすると、パブリック向けのルーティング書いてないっぽいので踏み台 SSH つながらないかも・・・
AWSTemplateFormatVersion: 2010-09-09
Resources:
subnetName:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
VpcId: !ImportValue MainVpcId
CidrBlock: 10.0.1.0/24
Tags:
- Key: Name
Value: PrivateSubnet
secGroupName:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: PrivateSecGrp
GroupDescription: PrivateSecGrp
VpcId: !ImportValue MainVpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 10.0.2.0/24
Tags:
- Key: Name
Value: MainVpc
Outputs:
PrivateSubnet:
Value: !Ref subnetName
Export:
Name: PrivateSubnet
パブリックサブネットに EC2 を配置する。
AWSTemplateFormatVersion: 2010-09-09
Resources:
myEC2Instance:
Type: AWS::EC2::Instance
Properties:
KeyName: PublicEc2Key
ImageId: ami-0992fc94ca0f1415a
InstanceType: t2.micro
Monitoring: false
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: "0"
GroupSet:
- !ImportValue PublicSecGrp
PrivateIpAddress: "10.0.2.10"
SubnetId: !ImportValue PublicSubnet
Tags:
- Key: Name
Value: PublicEC2
プライベートサブネットに EC2 を配置する。
AWSTemplateFormatVersion: 2010-09-09
Resources:
myEC2Instance:
Type: AWS::EC2::Instance
Properties:
KeyName: PrivateEc2Key
ImageId: ami-0992fc94ca0f1415a
InstanceType: t2.micro
Monitoring: false
NetworkInterfaces:
- AssociatePublicIpAddress: false
DeviceIndex: "0"
PrivateIpAddress: "10.0.1.15"
SubnetId: !ImportValue PrivateSubnet
Tags:
- Key: Name
Value: PrivateEC2
EC2 を テンプレートで定義すると(前回)
前回の内容と今回の内容を比べてみると驚くべきことがわかった。
AWSTemplateFormatVersion: 2010-09-09
Resources:
myEC2Instance:
Type: AWS::EC2::Instance
Properties:
KeyName: Mykeypair
ImageId: ami-0992fc94ca0f1415a
InstanceType: t2.micro
Monitoring: false
SecurityGroupIds:
- !ImportValue PublicSecGrp
SubnetId: !ImportValue PublicSubnet
Tags:
- Key: Name
Value: CFec2
こんな感じになるかと思うのですが
実はこれには一つ良くない点があります。
ネットワークインターフェイスにパブリック IP が振られないことです。
パブリック IP を AWS に振ってもらうには Properties の NetworkInterfacesで
AssociatePublicIpAddress を trueにしてあげなければなりません。
また、NetworkInterfacesで
サブネットとセキュリティグループ、プライベートIPアドレスの指定を書く場合は
他のプロパティに同じ記述を残してはいけません。
NetworkInterfaces 以外にも
サブネットとセキュリティグループ、プライベートIPアドレスの指定を書いた場合は
以下のようなエラーが出てロールバックが走ります。
Network interfaces and an instance-level subnet ID may not be specified on the
same request (Service: AmazonEC2; Status Code: 400; Error Code: >
InvalidParameterCombination; Request ID: c07729aa-c10f-4ce0-93a8-c800a92a3b32; Proxy: null)
EC2 を テンプレートで定義すると(今回)
前述の内容を踏まえて書き直すと。。。
AWSTemplateFormatVersion: 2010-09-09
Resources:
myEC2Instance:
Type: AWS::EC2::Instance
Properties:
KeyName: PublicEc2Key
ImageId: ami-0992fc94ca0f1415a
InstanceType: t2.micro
Monitoring: false
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: "0"
GroupSet:
- !ImportValue PublicSecGrp
PrivateIpAddress: "10.0.2.10"
SubnetId: !ImportValue PublicSubnet
Tags:
- Key: Name
Value: PublicEC2
見慣れないワードとして「DeviceIndex: "0"」があると思います。
これはイーサネットインターフェイスデバイスの番号を0とするという指定になります。
なぜ、0になるかと言えば
パブリックIPアドレスを割り当てることができるインターフェイスはeth0 つまり、0だからです。
余談
EC2のアクセスに鍵を使わない場合
今回はペアキーを利用することでEC2を構築しましたが
実際にはEC2をたくさん構築しないといけないので
一々、鍵を保持していたら運用面で支障が出ます。
かといってテンプレートに認証情報を埋め込むわけにいきません。
※セキュリティ的にもAWSのベストプラクティスにも反するので
認証情報を管理しなければ、EC2へのアクセスはできないので
管理しないという選択肢はありません。
じゃあどうすれば
AWS SSMもしくはAWS Secrets Managerを使いましょう。
また、AWS CLIを使って裏技っぽく構成に認証情報を含めないという方法もなくはないみたいですが
手動で実行しなければならない為、あまりオススメできません。
まとめ
Cloud Formation を利用して構築したVPC ネットワークにEC2 を構築しました。
もしかすると、プライベートサブネット向けのルーティングが
設定されていないので今の段階では踏み台SSHができないかもしれません。
次回は構築したネットワークの検証をやります。