AWS CLIを使ってパブリックとプライベートなサブネットを持つVPCを構築

Amazon Virtual Private Cloud の Getting Started Guide ドキュメントには、1 つのパブリックサブネットと1つのプライベートサブネットを持つ VPC を構築し、プライベートサブネットのインスタンスは、パブリックサブネット内に起動するネットワークアドレス変換(NAT)インスタンスを使用して、インターネットにアクセスするシステム例がある。

http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario2.html

VPC のウィザードで “VPC with Public and Private Subnets” を選択すれば楽にできるところを、コマンドラインツール AWS CLI からゴリゴリとやってみる。

 

Case2_Diagram

Step 1: Set Up the VPC and Internet Gateway

  • VPC(size/16)の作成
  • VPC にインターネットゲートウェイの設定
  • サブネット(size/24)の作成(public/private の 2 つ)
  • public subnet にインターネットゲートウェイへのルーティングを追加

を CLI で行う。

VPC作成

$ aws ec2 create-vpc --cidr-block  "10.4.0.0/16"
{
    "Vpc": {
        "InstanceTenancy": "default",
        "State": "pending",
        "VpcId": "vpc-xxxxxxxx",
        "CidrBlock": "10.4.0.0/16",
        "DhcpOptionsId": "dopt-zzzzzzzz"
    }
}

# VPC に名前をつける
$ aws ec2 create-tags --resources vpc-xxxxxxxx --tags Key=Name,Value="VPC with Public and Private Subnets"
{
    "return": "true"
}

インターネットゲートウェイ

VPC にインターネットゲートウェイを追加

# igw を作成
$ aws ec2 create-internet-gateway
{
    "InternetGateway": {
        "Tags": [],
        "InternetGatewayId": "igw-xxxxxxxx",
        "Attachments": []
    }
}

# vpc に igw を追加
$ aws ec2 attach-internet-gateway --internet-gateway-id igw-xxxxxxxx --vpc-id vpc-xxxxxxxx
{
    "return": "true"
}

# vpc の igw を確認
$ aws ec2 describe-internet-gateways --filters Name=attachment.vpc-id,Values=vpc-xxxxxxxx
{
    "InternetGateways": [
        {
            "Tags": [],
            "InternetGatewayId": "igw-xxxxxxxx",
            "Attachments": [
                {
                    "State": "available",
                    "VpcId": "vpc-xxxxxxxx"
                }
            ]
        }
    ]
}

サブネットの追加

  • public(10.4.0.0/24)
  • private(10.4.1.0/24)

の2つのサブネットを作成する。

まずは public subnet から。

# public subnet の作成
$ aws ec2 create-subnet --vpc-id vpc-xxxxxxxx --cidr-block "10.4.0.0/24"
{
    "Subnet": {
        "VpcId": "vpc-xxxxxxxx",
        "CidrBlock": "10.4.0.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1a",
        "SubnetId": "subnet-cccccccc",
        "AvailableIpAddressCount": 251
    }
}
$ aws ec2 create-tags --resources subnet-cccccccc --tags Key=Name,Value="public subnet"
{
    "return": "true"
}

次に private subnet を作成。

$ aws ec2 create-subnet --vpc-id vpc-xxxxxxxx --cidr-block "10.4.1.0/24"
{
    "Subnet": {
        "VpcId": "vpc-xxxxxxxx",
        "CidrBlock": "10.4.1.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1a",
        "SubnetId": "subnet-xxxxxxxx",
        "AvailableIpAddressCount": 251
    }
}

$ aws ec2 create-tags --resources subnet-xxxxxxxx --tags Key=Name,Value="private subnet"
{
    "return": "true"
}

VPC のサブネットを確認。

$ aws ec2 describe-subnets --filters Name=vpc-id,Values=vpc-xxxxxxxx
{
    "Subnets": [
        {
            "VpcId": "vpc-xxxxxxxx",
            "Tags": [
                {
                    "Value": "public subnet",
                    "Key": "Name"
                }
            ],
            "CidrBlock": "10.4.0.0/24",
            "MapPublicIpOnLaunch": false,
            "DefaultForAz": false,
            "State": "available",
            "AvailabilityZone": "ap-northeast-1a",
            "SubnetId": "subnet-cccccccc",
            "AvailableIpAddressCount": 251
        },
        {
            "VpcId": "vpc-xxxxxxxx",
            "Tags": [
                {
                    "Value": "private subnet",
                    "Key": "Name"
                }
            ],
            "CidrBlock": "10.4.1.0/24",
            "MapPublicIpOnLaunch": false,
            "DefaultForAz": false,
            "State": "available",
            "AvailabilityZone": "ap-northeast-1a",
            "SubnetId": "subnet-xxxxxxxx",
            "AvailableIpAddressCount": 251
        }
    ]
}

インターネットゲートウェイへのルーティングの追加

VPC のルーティングテーブルを確認。

$ aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-xxxxxxxx
{
    "RouteTables": [
        {
            "Associations": [
                {
                    "RouteTableAssociationId": "rtbassoc-dddddddd",
                    "Main": true,
                    "RouteTableId": "rtb-aaaaaaaa"
                }
            ],
            "RouteTableId": "rtb-aaaaaaaa",
            "VpcId": "vpc-xxxxxxxx",
            "PropagatingVgws": [],
            "Tags": [],
            "Routes": [
                {
                    "GatewayId": "local",
                    "DestinationCidrBlock": "10.4.0.0/16",
                    "State": "active",
                    "Origin": "CreateRouteTable"
                }
            ]
        }
    ]
}
# ルーティングテーブルに名前をつけておく
$ aws ec2 create-tags --resources rtb-aaaaaaaa --tags Key=Name,Value="route igw"
{
    "return": "true"
}

“Main”: true となっているルーティングは VPC 作成時についてくる、VPC 内の通信向けルーティング

VPC についてくる IGW を確認

$ aws ec2 describe-internet-gateways --filters Name=attachment.vpc-id,Values=vpc-xxxxxxxx
{
    "InternetGateways": [
        {
            "Tags": [],
            "InternetGatewayId": "igw-xxxxxxxx",
            "Attachments": [
                {
                    "State": "available",
                    "VpcId": "vpc-xxxxxxxx"
                }
            ]
        }
    ]
}

メインのルーティングテーブルにインターネットゲートウェイを関連付ける。

$ aws ec2 create-route --route-table-id rtb-aaaaaaaa --destination-cidr-block 0.0.0.0/0 --gateway-id igw-xxxxxxxx
{
    "return": "true"
}

public subnet にアタッチ

$ aws ec2 associate-route-table --route-table-id  rtb-aaaaaaaa --subnet-id subnet-cccccccc
{
    "AssociationId": "rtbassoc-19aeb57b"
}

VPC のルーティングを再確認

$ aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-xxxxxxxx
{
    "RouteTables": [
        {
            "Associations": [
                {
                    "RouteTableAssociationId": "rtbassoc-dddddddd",
                    "Main": true,
                    "RouteTableId": "rtb-aaaaaaaa"
                },
                {
                    "SubnetId": "subnet-cccccccc",
                    "RouteTableAssociationId": "rtbassoc-19aeb57b",
                    "RouteTableId": "rtb-aaaaaaaa"
                }
            ],
            "RouteTableId": "rtb-aaaaaaaa",
            "VpcId": "vpc-xxxxxxxx",
            "PropagatingVgws": [],
            "Tags": [
                {
                    "Value": "route igw",
                    "Key": "Name"
                }
            ],
            "Routes": [
                {
                    "GatewayId": "local",
                    "DestinationCidrBlock": "10.4.0.0/16",
                    "State": "active",
                    "Origin": "CreateRouteTable"
                },
                {
                    "GatewayId": "igw-xxxxxxxx",
                    "DestinationCidrBlock": "0.0.0.0/0",
                    "State": "active",
                    "Origin": "CreateRoute"
                }
            ]
        }
    ]
}

Step 2: Set Up a Security Group for Your VPC

VPC にセキュリティグループを設定する。

セキュリティグループは

  • WebServerSG(public subnet)
  • NATSG(public subnet)
  • DBServerSG(private subnet)

の3種類を作成。

public subnet の Web サーバー向け SG の作成

$ aws ec2 create-security-group --group-name WebServerSG --description "WebServerSG" --vpc-id vpc-xxxxxxxx
{
    "return": "true",
    "GroupId": "sg-iiiiiiii"
}

http://docs.aws.amazon.com/cli/latest/reference/ec2/create-security-group.html
http://docs.aws.amazon.com/cli/latest/userguide/cli-ec2-sg.html

・inbound

$ aws ec2 authorize-security-group-ingress --group-id sg-iiiiiiii --protocol tcp --port 22 --cidr 0.0.0.0/0
{
    "return": "true"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-iiiiiiii --protocol tcp --port 80 --cidr 0.0.0.0/0
{
    "return": "true"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-iiiiiiii --protocol tcp --port 443 --cidr 0.0.0.0/0
{
    "return": "true"
}

・outbound

デフォルトのまま全許可

・設定を確認

$ aws ec2 describe-security-groups --filters Name=vpc-id,Values=vpc-xxxxxxxx Name="group-name",Values=WebServerSG
{
    "SecurityGroups": [
        {
            "IpPermissionsEgress": [
                {
                    "IpProtocol": "-1",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": []
                }
            ],
            "Description": "WebServerSG",
            "IpPermissions": [
                {
                    "ToPort": 22,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": [],
                    "FromPort": 22
                },
                {
                    "ToPort": 80,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": [],
                    "FromPort": 80
                },
                {
                    "ToPort": 443,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": [],
                    "FromPort": 443
                }
            ],
            "GroupName": "WebServerSG",
            "VpcId": "vpc-xxxxxxxx",
            "OwnerId": "000000000000",
            "GroupId": "sg-iiiiiiii"
        }
    ]
}

public subnet の NAT 向け SG の作成

$ aws ec2 create-security-group --group-name NATSG --description "NATSG" --vpc-id vpc-xxxxxxxx
{
    "return": "true",
    "GroupId": "sg-jjjjjjjj"
}

・inbound

VPC 内からの SSH と private subnet からの 80/443 ポートだけ許可する。

$ aws ec2 authorize-security-group-ingress --group-id sg-jjjjjjjj --protocol tcp --port 22 --cidr 10.4.0.0/16
{
    "return": "true"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-jjjjjjjj --protocol tcp --port 80 --cidr 10.4.1.0/0
{
    "return": "true"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-jjjjjjjj --protocol tcp --port 443 --cidr 10.4.1.0/0
{
    "return": "true"
}

・outbound

デフォルトのまま全許可

・設定を確認

$ aws ec2 describe-security-groups --filters Name=vpc-id,Values=vpc-xxxxxxxx Name="group-name",Values=NATSG
{
    "SecurityGroups": [
        {
            "IpPermissionsEgress": [
                {
                    "IpProtocol": "-1",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": []
                }
            ],
            "Description": "NATSG",
            "IpPermissions": [
                {
                    "ToPort": 22,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "10.4.0.0/16"
                        }
                    ],
                    "UserIdGroupPairs": [],
                    "FromPort": 22
                },
                {
                    "ToPort": 80,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": [],
                    "FromPort": 80
                },
                {
                    "ToPort": 443,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": [],
                    "FromPort": 443
                }
            ],
            "GroupName": "NATSG",
            "VpcId": "vpc-xxxxxxxx",
            "OwnerId": "000000000000",
            "GroupId": "sg-jjjjjjjj"
        }
    ]
}

private subnet の DB 向け SG の作成

$ aws ec2 create-security-group --group-name DBServerSG --description "DBServerSG" --vpc-id vpc-xxxxxxxx
{
    "return": "true",
    "GroupId": "sg-bbbbbbbb"
}

・inbound

VPC 内からの SSH と WebServerSG からの memcached 用の 11211 ポートだけ許可する。

–source-group には web security group のリソース id を指定

$ aws ec2 authorize-security-group-ingress --group-id sg-bbbbbbbb --protocol tcp --port 11211 --source-group sg-iiiiiiii
{
    "return": "true"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-bbbbbbbb --protocol tcp --port 22 --cidr 10.4.0.0/16
{
    "return": "true"
}

・outbound

デフォルトのまま全許可

・設定を確認

$ aws ec2 describe-security-groups --filters Name=vpc-id,Values=vpc-xxxxxxxx Name="group-name",Values=DBServerSG
{
    "SecurityGroups": [
        {
            "IpPermissionsEgress": [
                {
                    "IpProtocol": "-1",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "UserIdGroupPairs": []
                }
            ],
            "Description": "DBServerSG",
            "IpPermissions": [
                {
                    "ToPort": 22,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "10.4.0.0/16"
                        }
                    ],
                    "UserIdGroupPairs": [],
                    "FromPort": 22
                },
                {
                    "ToPort": 11211,
                    "IpProtocol": "tcp",
                    "IpRanges": [],
                    "UserIdGroupPairs": [
                        {
                            "UserId": "000000000000",
                            "GroupId": "sg-iiiiiiii"
                        }
                    ],
                    "FromPort": 11211
                }
            ],
            "GroupName": "DBServerSG",
            "VpcId": "vpc-xxxxxxxx",
            "OwnerId": "000000000000",
            "GroupId": "sg-bbbbbbbb"
        }
    ]
}

Step 3: Launch an Instance into Your VPC

VPC 内で

  • nat
  • web server
  • db(memcached)

の3つのインスタンスを起動させる。

鍵の登録

まずは EC2 インスタンスに SSH でログインするための公開鍵を登録

http://docs.aws.amazon.com/AmazonVPC/latest/GettingStartedGuide/LaunchInstance.html

$ aws ec2 import-key-pair --key-name amzn-linux --public-key-material file://id_rsa.pub
{
    "KeyName": "amzn-linux",
    "KeyFingerprint": "d8:d6:79:0f:18:9b:c9:db:62:05:1b:65:bc:ab:63:03"
}

NAT インスタンスを探す

$ aws ec2 describe-images --owner amazon --region ap-northeast-1 --filter Name=name,Values=*amzn-ami-vpc-nat*
{
    "Images": [
        {
            "VirtualizationType": "paravirtual",
            "Name": "amzn-ami-vpc-nat-pv-2013.03.1.x86_64-ebs",
            "Hypervisor": "xen",
            "ImageOwnerAlias": "amazon",
            "ImageId": "ami-5f840e5e",
            "RootDeviceType": "ebs",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/sda1",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-e6ff7ac4",
                        "VolumeSize": 8,
                        "VolumeType": "standard"
                    }
                }
            ],
            "Architecture": "x86_64",
            "ImageLocation": "amazon/amzn-ami-vpc-nat-pv-2013.03.1.x86_64-ebs",
            "KernelId": "aki-44992845",
            "OwnerId": "137112412989",
            "RootDeviceName": "/dev/sda1",
            "Public": true,
            "ImageType": "machine",
            "Description": "Amazon Linux AMI VPC NAT x86_64 PV"
        },
        {
            "VirtualizationType": "paravirtual",
            "Name": "amzn-ami-vpc-nat-pv-2013.09.0.x86_64-ebs",
            "Hypervisor": "xen",
            "ImageOwnerAlias": "amazon",
            "ImageId": "ami-cd43d9cc",
            "RootDeviceType": "ebs",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/sda1",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-b9b9e39c",
                        "VolumeSize": 8,
                        "VolumeType": "standard"
                    }
                }
            ],
            "Architecture": "x86_64",
            "ImageLocation": "amazon/amzn-ami-vpc-nat-pv-2013.09.0.x86_64-ebs",
            "KernelId": "aki-176bf516",
            "OwnerId": "137112412989",
            "RootDeviceName": "/dev/sda1",
            "Public": true,
            "ImageType": "machine",
            "Description": "Amazon Linux AMI VPC NAT x86_64 PV"
        }
    ]
}

インスタンスの起動(WEB)

VPC 内にマイクロインスタンス(–instance-type t1.micro)を起動させるます。

起動時に Step1 で作成した public subnet と Step 2 で作成したセキュリティグループ(WebServerSG)を指定する。

$ aws ec2 run-instances --image-id ami-a1bec3a0 --count 1 --instance-type t1.micro --key-name amzn-linux --security-group-ids sg-iiiiiiii --subnet-id subnet-cccccccc --private-ip-address 10.4.0.6 --associate-public-ip-address
{
    "OwnerId": "000000000000",
    "ReservationId": "r-kkkkkkkk",
    "Groups": [],
    "Instances": [
        {
            "Monitoring": {
                "State": "disabled"
            },
            "PublicDnsName": null,
            "KernelId": "aki-176bf516",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "EbsOptimized": false,
            "LaunchTime": "2014-04-11T17:38:40.000Z",
            "PrivateIpAddress": "10.4.0.6",
            "ProductCodes": [],
            "VpcId": "vpc-xxxxxxxx",
            "StateTransitionReason": null,
            "InstanceId": "i-gggggggg",
            "ImageId": "ami-a1bec3a0",
            "PrivateDnsName": "ip-10-4-0-6.ap-northeast-1.compute.internal",
            "KeyName": "amzn-linux",
            "SecurityGroups": [
                {
                    "GroupName": "WebServerSG",
                    "GroupId": "sg-iiiiiiii"
                }
            ],
            "ClientToken": null,
            "SubnetId": "subnet-cccccccc",
            "InstanceType": "t1.micro",
            "NetworkInterfaces": [
                {
                    "Status": "in-use",
                    "SourceDestCheck": true,
                    "VpcId": "vpc-xxxxxxxx",
                    "Description": null,
                    "NetworkInterfaceId": "eni-llllllll",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateIpAddress": "10.4.0.6"
                        }
                    ],
                    "Attachment": {
                        "Status": "attaching",
                        "DeviceIndex": 0,
                        "DeleteOnTermination": true,
                        "AttachmentId": "eni-attach-86f14081",
                        "AttachTime": "2014-04-11T17:38:40.000Z"
                    },
                    "Groups": [
                        {
                            "GroupName": "WebServerSG",
                            "GroupId": "sg-iiiiiiii"
                        }
                    ],
                    "SubnetId": "subnet-cccccccc",
                    "OwnerId": "000000000000",
                    "PrivateIpAddress": "10.4.0.6"
                }
            ],
            "SourceDestCheck": true,
            "Placement": {
                "Tenancy": "default",
                "GroupName": null,
                "AvailabilityZone": "ap-northeast-1a"
            },
            "Hypervisor": "xen",
            "BlockDeviceMappings": [],
            "Architecture": "x86_64",
            "StateReason": {
                "Message": "pending",
                "Code": "pending"
            },
            "RootDeviceName": "/dev/sda1",
            "VirtualizationType": "paravirtual",
            "RootDeviceType": "ebs",
            "AmiLaunchIndex": 0
        }
    ]
}

管理しやすいように、名前をつけます

$ aws ec2 create-tags --resources i-gggggggg --tags Key=Name,Value="WEB Instance"
{
    "return": "true"
}

SSH できることを確認します。

$ ssh -i amzn-linux.pem ec2-user@ip.address.of.webinstance
[ec2-user@ip-10-4-0-5 ~]$

インスタンスの起動(NAT)

VPC 内にマイクロインスタンス(–instance-type t1.micro)を起動させる。

起動時に Step1 で作成した public subnet と Step 2 で作成したセキュリティグループ(NATSG)を指定する。
–associate-public-ip-address オプションをつけると、public IP アドレスが付与される。(Elastic IP でグローバルな固定IPをふることもできる)

$ aws ec2 run-instances --image-id ami-cd43d9cc --count 1 --instance-type t1.micro --key-name amzn-linux --security-group-ids sg-jjjjjjjj --subnet-id subnet-cccccccc --private-ip-address 10.4.0.5 --associate-public-ip-address
{
    "OwnerId": "000000000000",
    "ReservationId": "r-2b81362d",
    "Groups": [],
    "Instances": [
        {
            "Monitoring": {
                "State": "disabled"
            },
            "PublicDnsName": null,
            "KernelId": "aki-176bf516",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "EbsOptimized": false,
            "LaunchTime": "2014-04-11T17:19:33.000Z",
            "PrivateIpAddress": "10.4.0.5",
            "ProductCodes": [],
            "VpcId": "vpc-xxxxxxxx",
            "StateTransitionReason": null,
            "InstanceId": "i-hhhhhhhh",
            "ImageId": "ami-cd43d9cc",
            "PrivateDnsName": "ip-10-4-0-5.ap-northeast-1.compute.internal",
            "KeyName": "amzn-linux",
            "SecurityGroups": [
                {
                    "GroupName": "NATSG",
                    "GroupId": "sg-jjjjjjjj"
                }
            ],
            "ClientToken": null,
            "SubnetId": "subnet-cccccccc",
            "InstanceType": "t1.micro",
            "NetworkInterfaces": [
                {
                    "Status": "in-use",
                    "SourceDestCheck": true,
                    "VpcId": "vpc-xxxxxxxx",
                    "Description": null,
                    "NetworkInterfaceId": "eni-d7b45ea0",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateIpAddress": "10.4.0.5"
                        }
                    ],
                    "Attachment": {
                        "Status": "attaching",
                        "DeviceIndex": 0,
                        "DeleteOnTermination": true,
                        "AttachmentId": "eni-attach-55f34252",
                        "AttachTime": "2014-04-11T17:19:33.000Z"
                    },
                    "Groups": [
                        {
                            "GroupName": "NATSG",
                            "GroupId": "sg-jjjjjjjj"
                        }
                    ],
                    "SubnetId": "subnet-cccccccc",
                    "OwnerId": "000000000000",
                    "PrivateIpAddress": "10.4.0.5"
                }
            ],
            "SourceDestCheck": true,
            "Placement": {
                "Tenancy": "default",
                "GroupName": null,
                "AvailabilityZone": "ap-northeast-1a"
            },
            "Hypervisor": "xen",
            "BlockDeviceMappings": [],
            "Architecture": "x86_64",
            "StateReason": {
                "Message": "pending",
                "Code": "pending"
            },
            "RootDeviceName": "/dev/sda1",
            "VirtualizationType": "paravirtual",
            "RootDeviceType": "ebs",
            "AmiLaunchIndex": 0
        }
    ]
}

管理しやすいように、名前をつけます

$ aws ec2 create-tags --resources i-hhhhhhhh --tags Key=Name,Value="NAT Instance"
{
    "return": "true"
}

NAT インスタンス固有の設定変更

NAT インスタンスなので、経由するトラフィックの source/destination をチェックしないようにします。

Each EC2 instance performs source/destination checks by default. This means that the instance must be the source or destination of any traffic it sends or receives. However, a NAT instance must be able to send and receive traffic when the source or destination is not itself. Therefore, you must disable source/destination checks on the NAT instance.
http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_NAT_Instance.html#EIP_Disable_SrcDestCheck

CLI からは aws ec2 modify-instance-attribute で変更します。


$ aws ec2 modify-instance-attribute --instance-id i-hhhhhhhh --source-dest-check "{\"Value\": false}"
{
    "return": "true"
}

$ aws ec2 describe-instance-attribute  --instance-id i-hhhhhhhh --attribute sourceDestCheck
{
    "UserData": {},
    "sourceDestCheck": {
        "value": "false"
    },
    "ProductCodes": [],
    "InstanceId": "i-hhhhhhhh",
    "InstanceInitiatedShutdownBehavior": {},
    "SriovNetSupport": {},
    "RootDeviceName": {},
    "EbsOptimized": {},
    "BlockDeviceMappings": [],
    "KernelId": {},
    "RamdiskId": {},
    "DisableApiTermination": {},
    "InstanceType": {}
}

NAT インスタンスに Web サーバ経由で SSH します。

外につながることを確認します。

$ curl www.google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=qqVBU7udM-HU8gfJzYCIAQ">here</A>.
</BODY></HTML>

インスタンスの起動(DB)

★NAT向けのルーティングを作成

$ aws ec2 create-route-table --vpc-id vpc-xxxxxxxx
{
    "RouteTable": {
        "Associations": [],
        "RouteTableId": "rtb-cf213aad",
        "VpcId": "vpc-xxxxxxxx",
        "PropagatingVgws": [],
        "Tags": [],
        "Routes": [
            {
                "GatewayId": "local",
                "DestinationCidrBlock": "10.4.0.0/16",
                "State": "active",
                "Origin": "CreateRouteTable"
            }
        ]
    }
}

管理しやすいように、名前をつけます

$ aws ec2 create-tags --resources rtb-cf213aad --tags Key=Name,Value="route nat"
{
    "return": "true"
}

インスタンス作成前に、先ほど追加した NAT インスタンスへのルーティングを追加
–instances-id で NAT インスタンスを指定。

$ aws ec2 create-route --route-table-id rtb-cf213aad --destination-cidr-block  0.0.0.0/0 --instance-id i-hhhhhhhh
{
    "return": "true"
}
$ aws ec2 associate-route-table --route-table-id rtb-cf213aad  --subnet-id subnet-xxxxxxxx
{
    "AssociationId": "rtbassoc-c7a3b8a5"
}

$ aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-xxxxxxxx
{
    "RouteTables": [
        {
            "Associations": [
                {
                    "SubnetId": "subnet-xxxxxxxx",
                    "RouteTableAssociationId": "rtbassoc-c7a3b8a5",
                    "RouteTableId": "rtb-cf213aad"
                }
            ],
            "RouteTableId": "rtb-cf213aad",
            "VpcId": "vpc-xxxxxxxx",
            "PropagatingVgws": [],
            "Tags": [
                {
                    "Value": "route nat",
                    "Key": "Name"
                }
            ],
            "Routes": [
                {
                    "GatewayId": "local",
                    "DestinationCidrBlock": "10.4.0.0/16",
                    "State": "active",
                    "Origin": "CreateRouteTable"
                },
                {
                    "Origin": "CreateRoute",
                    "DestinationCidrBlock": "0.0.0.0/0",
                    "InstanceId": "i-hhhhhhhh",
                    "NetworkInterfaceId": "eni-d7b45ea0",
                    "State": "active",
                    "InstanceOwnerId": "000000000000"
                }
            ]
        },
        {
            "Associations": [
                {
                    "RouteTableAssociationId": "rtbassoc-dddddddd",
                    "Main": true,
                    "RouteTableId": "rtb-aaaaaaaa"
                },
                {
                    "SubnetId": "subnet-cccccccc",
                    "RouteTableAssociationId": "rtbassoc-19aeb57b",
                    "RouteTableId": "rtb-aaaaaaaa"
                }
            ],
            "RouteTableId": "rtb-aaaaaaaa",
            "VpcId": "vpc-xxxxxxxx",
            "PropagatingVgws": [],
            "Tags": [],
            "Routes": [
                {
                    "GatewayId": "local",
                    "DestinationCidrBlock": "10.4.0.0/16",
                    "State": "active",
                    "Origin": "CreateRouteTable"
                },
                {
                    "GatewayId": "igw-xxxxxxxx",
                    "DestinationCidrBlock": "0.0.0.0/0",
                    "State": "active",
                    "Origin": "CreateRoute"
                }
            ]
        }
    ]
}

VPC 内にマイクロインスタンス(–instance-type t1.micro)を起動させる。
起動時に Step1 で作成した public subnet と Step 2 で作成したセキュリティグループ(DBServerSG)を指定する。
–no-associate-public-ip-address オプションをつけて、public IP アドレスは付与しない。

$ aws ec2 run-instances --image-id ami-a1bec3a0 --count 1 --instance-type t1.micro --key-name amzn-linux --security-group-ids sg-bbbbbbbb --subnet-id subnet-xxxxxxxx  --private-ip-address 10.4.1.5 --no-associate-public-ip-address
{
    "OwnerId": "000000000000",
    "ReservationId": "r-508c3b56",
    "Groups": [],
    "Instances": [
        {
            "Monitoring": {
                "State": "disabled"
            },
            "PublicDnsName": null,
            "KernelId": "aki-176bf516",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "EbsOptimized": false,
            "LaunchTime": "2014-04-11T17:50:22.000Z",
            "PrivateIpAddress": "10.4.1.5",
            "ProductCodes": [],
            "VpcId": "vpc-xxxxxxxx",
            "StateTransitionReason": null,
            "InstanceId": "i-ffffffff",
            "ImageId": "ami-a1bec3a0",
            "PrivateDnsName": "ip-10-4-1-5.ap-northeast-1.compute.internal",
            "KeyName": "amzn-linux",
            "SecurityGroups": [
                {
                    "GroupName": "DBServerSG",
                    "GroupId": "sg-bbbbbbbb"
                }
            ],
            "ClientToken": null,
            "SubnetId": "subnet-xxxxxxxx",
            "InstanceType": "t1.micro",
            "NetworkInterfaces": [
                {
                    "Status": "in-use",
                    "SourceDestCheck": true,
                    "VpcId": "vpc-xxxxxxxx",
                    "Description": null,
                    "NetworkInterfaceId": "eni-538b6124",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateIpAddress": "10.4.1.5"
                        }
                    ],
                    "Attachment": {
                        "Status": "attaching",
                        "DeviceIndex": 0,
                        "DeleteOnTermination": true,
                        "AttachmentId": "eni-attach-e1f041e6",
                        "AttachTime": "2014-04-11T17:50:22.000Z"
                    },
                    "Groups": [
                        {
                            "GroupName": "DBServerSG",
                            "GroupId": "sg-bbbbbbbb"
                        }
                    ],
                    "SubnetId": "subnet-xxxxxxxx",
                    "OwnerId": "000000000000",
                    "PrivateIpAddress": "10.4.1.5"
                }
            ],
            "SourceDestCheck": true,
            "Placement": {
                "Tenancy": "default",
                "GroupName": null,
                "AvailabilityZone": "ap-northeast-1a"
            },
            "Hypervisor": "xen",
            "BlockDeviceMappings": [],
            "Architecture": "x86_64",
            "StateReason": {
                "Message": "pending",
                "Code": "pending"
            },
            "RootDeviceName": "/dev/sda1",
            "VirtualizationType": "paravirtual",
            "RootDeviceType": "ebs",
            "AmiLaunchIndex": 0
        }
    ]
}

$ aws ec2 create-tags --resources i-ffffffff --tags Key=Name,Value="DB Instance"
{
    "return": "true"
}

踏み台経由で DB インスタンスに ssh します。
yum で memcached と telnet をインストールします。
NAT 経由でインターネットにでれるようになっているならば、 yum コマンドも使えます。

$ sudo yum install -y memcached telnet
$ sudo service memcached start
Starting memcached:                                        [  OK  ]

DB インスタンスからローカルホストの memcached の 起動を確認

[ec2-user@ip-10-4-1-5 ~]$ echo version | nc localhost 11211
VERSION 1.4.13

Web インスタンスからリモートホストの memcached の 起動を確認

[ec2-user@ip-10-4-0-6 ~]$ echo version | nc 10.4.1.5 11211
VERSION 1.4.13

MEMO

NAT インスタンスのカスタマイズ

NAT 向けの設定は起動時に /etc/rc.local から/usr/local/sbin/configure-pat.sh を呼び出して設定しているようです。

このスクリプトで設定を行っている箇所を抜粋

sysctl -q -w net.ipv4.ip_forward=1 net.ipv4.conf.eth0.send_redirects=0 && (
   iptables -t nat -C POSTROUTING -o eth0 -s ${VPC_CIDR_RANGE} -j MASQUERADE 2> /dev/null ||
   iptables -t nat -A POSTROUTING -o eth0 -s ${VPC_CIDR_RANGE} -j MASQUERADE ) ||
       die

sysctl net.ipv4.ip_forward net.ipv4.conf.eth0.send_redirects | log
iptables -n -t nat -L POSTROUTING | log

IP マスカレード

iptables -t nat -A POSTROUTING -o eth0 -s ${VPC_CIDR_RANGE} -j MASQUERADEIP マスカレードしている。

RedHat Linux のマニュアルに同じコマンドの説明があるので引用。

To allow LAN nodes with private IP addresses to communicate with external public networks, configure the firewall for IP masquerading, which masks requests from LAN nodes with the IP address of the firewall’s external device (in this case, eth0):

~]# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

This rule uses the NAT packet matching table (-t nat) and specifies the built-in POSTROUTING chain for NAT (-A POSTROUTING) on the firewall’s external networking device (-o eth0).
POSTROUTING allows packets to be altered as they are leaving the firewall’s external device.
The -j MASQUERADE target is specified to mask the private IP address of a node with the external IP address of the firewall/gateway.

https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/sect-Security_Guide-Firewalls-FORWARD_and_NAT_Rules.html

IPv4 パケット転送を許可

sysctl net.ipv4.ip_forward net.ipv4.conf.eth0.send_redirectsIPv4 パケット転送を許可している。

RedHat Linux のマニュアルに同じコマンドの説明があるので引用

By default, the IPv4 policy in Red Hat Enterprise Linux kernels disables support for IP forwarding. This prevents machines that run Red Hat Enterprise Linux from functioning as dedicated edge routers. To enable IP forwarding, use the following command as the root user:

~]# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

This configuration change is only valid for the current session; it does not persist beyond a reboot or network service restart. To permanently set IP forwarding, edit the /etc/sysctl.conf file as follows: Locate the following line:

net.ipv4.ip_forward = 0

Edit it to read as follows:

net.ipv4.ip_forward = 1

As the root user, run the following command to enable the change to the sysctl.conf file:

~]# sysctl -p /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
[output truncated]

https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/sect-Security_Guide-Firewalls-FORWARD_and_NAT_Rules.html

また iptables ... -C || iptables ... -A というようにして、ルールが存在しない場合(=初回起動時)のみルール追加している。

実際に、起動時の syslog を確認すると

Apr 11 15:21:16 ip-10-4-0-5 vpc: Determining the MAC address on eth0...
Apr 11 15:21:16 ip-10-4-0-5 vpc: Found MAC 06:b0:63:98:ef:3e for eth0.
Apr 11 15:21:16 ip-10-4-0-5 vpc: Metadata location for vpc ipv4 range: http://169.254.169.254/latest/meta-data/network/interfaces/macs/06:b0:63:98:ef:3e/vpc-ipv4-cidr-block
Apr 11 15:21:16 ip-10-4-0-5 vpc: Retrieved VPC CIDR range 10.4.0.0/16 from meta-data.
Apr 11 15:21:16 ip-10-4-0-5 vpc: Enabling PAT...
Apr 11 15:21:16 ip-10-4-0-5 kernel: [   86.409473] ip_tables: (C) 2000-2006 Netfilter Core Team
Apr 11 15:21:16 ip-10-4-0-5 kernel: [   86.416675] nf_conntrack version 0.5.0 (4753 buckets, 19012 max)
Apr 11 15:21:16 ip-10-4-0-5 vpc: net.ipv4.ip_forward = 1
Apr 11 15:21:16 ip-10-4-0-5 vpc: net.ipv4.conf.eth0.send_redirects = 0
Apr 11 15:21:16 ip-10-4-0-5 vpc: Chain POSTROUTING (policy ACCEPT)
Apr 11 15:21:16 ip-10-4-0-5 vpc: target     prot opt source               destination
Apr 11 15:21:16 ip-10-4-0-5 vpc: MASQUERADE  all  --  10.4.0.0/16          0.0.0.0/0
Apr 11 15:21:16 ip-10-4-0-5 vpc: Configuration of PAT complete.

というようになっている。

また、実際に設定を確認すると

$ sudo iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  10.4.0.0/16          0.0.0.0/0

$ sudo sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

というようになっている。

outbound を制限する

セキュリティグループのデフォルト設定ではすべての outbound を許可している。
この outbound 設定を禁止するには以下を実行する。

$ aws ec2 revoke-security-group-egress  --group-id sg-XXXXXX --protocol -1  --port -1 --cidr 0.0.0.0/0
{
    "return": "true"
}

References

Advertisements
Tagged with: , ,
Posted in aws

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
%d bloggers like this: