今日を知り、明日を変えるシステム運用メディア

PythonとBoto3を使用して、AWSのインフラ構築を自動化してみた

PythonとBoto3を使用して、AWSのインフラ構築を自動化してみた

はじめに

はじめに

昨今、サーバ運用・構築などをオンプレミスから、AWSやGoogle Cloud、Microsoft Azure などのクラウドへ移行する企業が増え続けています。

クラウドはオンプレミスと比べて導入コストを抑えることができメリットがたくさんありますが、コンソール上でボタンクリックやフォームに情報を入力するなど、手動で行う作業を面倒に感じる方もいらっしゃるかと思います。

そこで、活躍するのが、インフラ構築自動化につながるソリューションの導入です。今回はクラウドの中でも特にシェア率が高いAWSのインフラ構築を、PythonとBoto3を使用して自動化する方法をご紹介します。

インフラ構築の自動化に期待できるメリット

そもそもインフラ構築を自動化することは、どのようなメリットが期待できるのでしょうか。ポイントは以下の通りです。

  • 業務の効率化
  • コストの削減
  • ヒューマンエラーの回避

インフラ構築に限らず、業務の自動化はそのまま効率的な業務プロセスの実現に役立ちます。有人での対応負担が減るので、リソースを余分に確保する必要がなくなります。

また、人件費を抑えてコストの削減を進める上でも有効です。人件費の高騰により人材確保が進まない場合、業務自動化が大きな転換点となることがあります。

業務が無人対応となることで、ヒューマンエラーを回避できるというメリットも魅力的です。人間であれば必ず発生すると考えるべきケアレスミスのリスクを、ほぼ丸ごと解消できます。

Boto3(AWS SDK for Python)とは?

Boto3(AWS SDK for Python)とは?

今回使用するBoto3について簡単に説明します。 Boto3とは、「AWS SDK for Python」のことで、AWS の各種サービス(Amazon S3、Amazon EC2、Amazon RDSなど)をPythonから操作するためのライブラリです。これはAWSが公式で提供しています。Pythonのライブラリやアプリ、スクリプトを、そのままAWSに統合し、シームレスに運用を継続することが可能です。AWSへの移行が進まない理由の一つに、移行作業の負担が大きいという問題があります。Boto3は、そのような負担の発生を最小限に抑えられることから、システムのクラウド化を強力に推進できるソリューションです。

Pythonのバージョン 2.7、および3.4+ でのネイティブサポートを提供するべく、わざわざ基礎から構築されている点も、このサービスの信頼性の高さが評価されている理由と言えるでしょう。

また内部では、AWS CLIにも利用されている Botocore というライブラリを利用しています。

構成

今回はWEBアプリケーションを運用する想定で、VPC内にパブリックサブネットとプライベートサブネットがあり、インターネットゲートウェイ、EC2、RDSがあるシンプルなインフラ環境を構築します。

シンプルなインフラ環境

事前準備

事前準備

1. 前提条件

今回検証するにあたり、以下3つの条件が必要になります。

自分のPCにPython3系がインストールされていること

Boto3がインストールされていること

AWSアカウントを作成していること

今回、Pythonのバージョンは3.9を使用しています。

2. AWSアクセスキー・シークレットアクセスキーの用意

以下のアクセスポリシーが付与されているIAMユーザー、IAMグループを用意し、そのユーザーのアクセスキー、シークレットアクセスキーを用意してください。

アクセスポリシー名

AmazonEC2FullAccess

AmazonRDSFullAccess

コーディング方法

全体の流れは以下になります。

1. VPCを作成
2. 作成したVPCにプライベートサブネットを作成
3. 作成したVPCにパブリックサブネットを作成
4. 作成したパブリックサブネットにEC2インスタンスを作成
5. RDS用のサブネットグループを作成
6. RDSインスタンスを作成

今回作成するプログラムはこれら6つの工程をBoto3で作成していきます。

まず、使用したいサービス、リージョン、アベイラビリティゾーンなどを設定するメソッドと、タグを作成するメソッドを作成します。

# config(設定)メソッド
def __awsConfig(self, service):
  # 引数で使用するサービスを指定、リージョン・アベイラビリティゾーンはインスタンス変数を指定
  client = boto3.client(
    service,
    aws_access_key_id = self.access_key,
    aws_secret_access_key = self.secret_access_key,
    region_name = self.region_name
  )
  return client

config設定メソッドは、引数にサービス(ec2、rdsなど)を指定します。

# タグ作成メソッド
def __createTags(self, client, id, name):
  # 指定したidの各サービスにNameタグ、Ownerタグをつける
  tags = client.create_tags(
    Resources=[id], 
    Tags=[
      {'Key': 'Name', 'Value': name},
      {'Key': 'Owner', 'Value': '〓メールアドレス〓'}
    ]
  )
  return tags

タグ作成メソッドは、引数にconfigメソッドのサービスと、各サービス(EC2)などのid、タグ名を指定します。

1. VPCの作成

東京リージョンにVPCを作成します。

# VPC作成メソッド
def __createVpc(self):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # vpcの作成
  vpc = client.create_vpc(CidrBlock='10.0.0.0/16', InstanceTenancy='default')
  # vpcのidを取得
  id = vpc['Vpc']['VpcId']
  
  # 作成したVPCにタグをつける
  tags = self.__createTags(client, id, 'test-vpc')
  return id

create_vpc()でVPCを作成します。引数にはCIDRブロック、テナンシーを指定します。

VPCの次はプライベートサブネットを作成します。

2. プライベートサブネットの作成

「1. VPCの作成」で作成したVPCにプライベートサブネットを作成します。 後続でパブリックサブネットも作成するので、サブネット作成を使いまわせるようにサブネット作成のみのメソッドを作成しました。

# サブネット作成メソッド
def __createSubnet(self, vpc_id, availability_zone, cidr_block, name):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # サブネットの作成
  subnet = client.create_subnet(AvailabilityZone=availability_zone, CidrBlock=cidr_block, VpcId=vpc_id)
  # サブネットのidを取得
  id = subnet['Subnet']['SubnetId']
  
  # 作成したサブネットにタグをつける
  tags = self.__createTags(client, id, name)
  return id

create_subnet()でサブネットを作成します。引数にはアベイラビリティゾーン、CIDRブロック、作成したVPCのidを指定します。

CIDRブロックが「10.0.2.0/24」「10.0.20.0/24」の2つのサブネットを、サブネット作成メソッドを使用して作成していきます。

# プライベートサブネット作成メソッド
def __createPrivateSubnet(self, vpc_id):
  availability_zone_list = [self.availability_zone_1, self.availability_zone_2]
  cidr_block_list = ['10.0.2.0/24', '10.0.20.0/24']
  name_list = ['private_subnet_1a', 'private_subnet_1c']
  subnet_id_list = []
  
  # アベイラビリティゾーン、CIDRブロックのリストをループさせ、作成したVPCにサブネットを作成
  for availability_zone, cidr_block, name in zip(availability_zone_list, cidr_block_list, name_list):
    
    # CIDRブロックが「10.0.2.0/24」「'10.0.20.0/24'」の2つのプライベートサブネットを作成
    subnet_id = self.__createSubnet(vpc_id, availability_zone, cidr_block, name)
    subnet_id_list.append(subnet_id)
    
  return subnet_id_list

プライベートサブネットが作成できたので、次はパブリックサブネットを作成します。

3. パブリックサブネットの作成

パブリックサブネットもプライベートサブネット同様、作成したVPCに、CIDRブロックが「10.0.1.0/24」のサブネットを作成します。

また、パブリックサブネット上にEC2インスタンスを作成し、インターネットと通信させる必要があるので、インターネットゲートウェイ、ルートテーブル、カスタムルートを作成します。

# パブリックサブネット作成メソッド
def __createPublicSubnet(self, vpc_id):
  # サブネット作成メソッドの呼び出し(CIDRブロックが「10.0.1.0/24」のパブリックサブネットを作成)
  subnet_id = self.__createSubnet(vpc_id, self.availability_zone_1, '10.0.1.0/24', 'public_subnet_1a')
  
  # インターネットゲートウェイ作成メソッドの呼び出し
  internet_gateway_id = self.__createInternetGateway(vpc_id)
  
  # ルートテーブル作成メソッドの呼び出し
  route_table_id = self.__createRouteTable(vpc_id)
  
  # カスタムルート作成メソッドの呼び出し
  create_route = self.__createRoute(internet_gateway_id, route_table_id, subnet_id)
  return subnet_id

パブリックサブネット作成メソッドでは、サブネット作成メソッド、インターネットゲートウェイ作成メソッド、ルートテーブル作成メソッド、カスタムルート作成メソッドを実行しています。 インターネットゲートウェイ作成メソッドから順に説明します。

# インターネットゲートウェイ作成メソッド
def __createInternetGateway(self, vpc_id):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  #インターネットゲートウェイの作成
  internet_gateway = client.create_internet_gateway()
  # インターネットゲートウェイのidを取得
  internet_gateway_id = internet_gateway['InternetGateway']['InternetGatewayId']
  
  # 作成したインターネットゲートウェイにタグをつける
  tags = self.__createTags(client, internet_gateway_id, 'test-igw')
  
  # インターネットゲートウェイをアタッチ
  attach = client.attach_internet_gateway(InternetGatewayId=internet_gateway_id, VpcId=vpc_id)
  return internet_gateway_id

create_internet_gateway()でインターネットゲートウェイを作成します。 インターネットゲートウェイの作成後、VPCにアタッチする必要があります。 アタッチはattach_internet_gateway()で行います。引数には作成したVPCのid、インターネットゲートウェイのidを指定します。

次に、ルートテーブルを作成します。

# ルートテーブル作成メソッド
def __createRouteTable(self, vpc_id):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # ルートテーブルの作成
  route_table = client.create_route_table(VpcId=vpc_id)
  # ルートテーブルのidを取得
  id = route_table['RouteTable']['RouteTableId']
  
  # 作成したルートテーブルにタグをつける
  tags = self.__createTags(client, id, 'test-public-route-table')
  return id

create_route_table()でルートテーブルを作成します。引数には作成したVPCのidを指定します。

ルートテーブルを作成した後にカスタムルートを作成します。

# カスタムルート作成メソッド
def __createRoute(self, gateway_id, route_table_id, subnet_id):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # 作成したルートテーブルにカスタムルートを作成(送信先「0.0.0.0/0」)
  create_route = client.create_route(DestinationCidrBlock='0.0.0.0/0', GatewayId=gateway_id, RouteTableId=route_table_id)
  
  # サブネットの関連付け
  associate_route_subnet = client.associate_route_table(RouteTableId=route_table_id, SubnetId=subnet_id)
  
  # パブリックIPアドレスを自動的に受信するように設定
  attribute_subnet = client.modify_subnet_attribute(
    MapPublicIpOnLaunch={'Value': True},
    SubnetId=subnet_id
  )
  
  return create_route

create_route()でカスタムルートを作成します。引数にCIDRブロック(送信先)、作成したインターネットゲートウェイのid、ルートテーブルのidを指定します。

作成したカスタムルートに、サブネットの関連付けを行います。このサブネットの関連付けを行うことにより、対象のサブネットがルートテーブルとインターネットゲートウェイによってインターネットに接続ができます。

associate_route_table()でサブネットの関連付けを行います。 引数にはサブネットのid、ルートテーブルのidを指定します。

4. EC2インスタンスの作成

「3. パブリックサブネットの作成」で作成したパブリックサブネット内に、EC2インスタンスを作成します。

# EC2インスタンス作成メソッド
def __createInstance(self, subnet_id, vpc_id, security_group_name):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # セキュリティグループ作成メソッドの呼び出し
  security_group_id = self.__createSecurityGroup(vpc_id, security_group_name)
  
  # キーペア作成メソッドの呼び出し
  key_name = self.__createKeyPair()
  
  # パブリックIPアドレスの自動割り当ての有効
  valid_auto_public_ip = client.modify_subnet_attribute(
    MapPublicIpOnLaunch={'Value': True},
    SubnetId=subnet_id
  )
  
  # AMIは「Amazon Linux2」を使用
  ami_id = 'ami-04204a8960917fd92'
  
  # EC2インスタンス作成
  ec2_instance = client.run_instances(
    ImageId=ami_id, 
    MinCount=1, 
    MaxCount=1, 
    InstanceType="t2.micro", 
    SecurityGroupIds=[security_group_id], 
    KeyName=key_name, 
    SubnetId=subnet_id
  )
  
  # インスタンスidの取得
  instance_id = ec2_instance['Instances'][0]['InstanceId']
  
  # インバウンドルール設定メソッド呼び出し
  inbound_rule = self.__settingInboundRules(security_group_id, 22)
  
  # 作成したインスタンスにタグをつける
  tags = self.__createTags(client, instance_id, 'test-web-server')
  return instance_id, security_group_id# EC2インスタンス作成メソッド
def __createInstance(self, subnet_id, vpc_id, security_group_name):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # セキュリティグループ作成メソッドの呼び出し
  security_group_id = self.__createSecurityGroup(vpc_id, security_group_name)
  
  # キーペア作成メソッドの呼び出し
  key_name = self.__createKeyPair()
  
  # パブリックIPアドレスの自動割り当ての有効
  valid_auto_public_ip = client.modify_subnet_attribute(
    MapPublicIpOnLaunch={'Value': True},
    SubnetId=subnet_id
  )
  
  # AMIは「Amazon Linux2」を使用
  ami_id = 'ami-04204a8960917fd92'
  
  # EC2インスタンス作成
  ec2_instance = client.run_instances(
    ImageId=ami_id, 
    MinCount=1, 
    MaxCount=1, 
    InstanceType="t2.micro", 
    SecurityGroupIds=[security_group_id], 
    KeyName=key_name, 
    SubnetId=subnet_id
  )
  
  # インスタンスidの取得
  instance_id = ec2_instance['Instances'][0]['InstanceId']
  
  # インバウンドルール設定メソッド呼び出し
  inbound_rule = self.__settingInboundRules(security_group_id, 22)
  
  # 作成したインスタンスにタグをつける
  tags = self.__createTags(client, instance_id, 'test-web-server')
  return instance_id, security_group_id

まず、インスタンス作成時に使用するEC2用のセキュリティグループを作成します。

# セキュリティグループ作成メソッド
def __createSecurityGroup(self, vpc_id, name):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # セキュリティグループ作成
  security_group = client.create_security_group(Description=name, GroupName=name, VpcId=vpc_id)
  
  # 作成したセキュリティグループのidを取得
  security_group_id = security_group['GroupId']
  
  # 作成したセキュリティグループにタグをつける
  tags = self.__createTags(client, security_group_id, name)
  return security_group_id

create_security_group()でセキュリティグループを作成します。引数にVPCのid、セキュリティグループ名、説明を指定します。

次に、EC2インスタンスにSSH接続するためのキーペアを作成します。

# SSH用のキーペア作成メソッド
def __createKeyPair(self):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # 鍵の名前
  key_name = 'test-key.pem'
  # キーペアの作成
  key = client.create_key_pair(KeyName=key_name)
  
  # キーペアidの取得
  key_pair_id = key['KeyPairId']
  
  # 作成したキーペアを取得し、pemファイルを作成
  key_material = key['KeyMaterial']
  with open(key_name, mode='w') as f:
    f.write(key_material)
  
  # 作成したキーペアにタグをつける
  tags = self.__createTags(client, key_pair_id, 'test-key-pair')
  return key_name

create_key_pair()でキーペアを作成します。引数には鍵のファイル名を指定します。 キーペアを作成した後、キーペアの情報を取得し作成します。

キーペアを作成した後に、パブリックIPアドレスの自動割り当てを有効化します。 modify_subnet_attribute()でパブリックIPアドレスを自動的に受信(自動割り当て)するように設定します。引数にはパブリックIPアドレスの割り当てをするのでTrue、作成したパブリックサブネットのidを指定します。

run_instances()でEC2インスタンスを作成します。 引数にAMIのid、インスタンスのタイプ、作成したセキュリティグループのリスト、作成したキーペア、作成したパブリックサブネットのidを指定します。

EC2インスタンスを作成した後に、SSH接続用のインバウンドルールを設定します。

 # インバウンドルール設定メソッド
def __settingInboundRules(self, security_group_id, port):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # マイIP(現在のグローバルIPアドレス)を取得
  url = 'https://ifconfig.me'
  request = requests.get(url)
  ip_address = '{}/32'.format(request.text)
  
  # インバウンドルールの作成
  inbound_rule = client.authorize_security_group_ingress(
    GroupId=security_group_id,
    IpPermissions=[
      {
        'FromPort': port,
        'IpProtocol': 'tcp',
        'IpRanges': [
          {
            'CidrIp': ip_address,
            'Description': 'test inbound rule',
          },
        ],
        'ToPort': port
      }
    ]
  )
  
  # セキュリティグループルール(インバウンドルール)idの取得
  inbound_rule_id = inbound_rule['SecurityGroupRules'][0]['SecurityGroupRuleId']
  
  # 作成したインバウンドルールにタグをつける
  tags = self.__createTags(client, inbound_rule_id, 'test-inbound-rule-ssh')
  return inbound_rule

下記サイトでマイIP(現在使用しているグローバルIPアドレス)を取得します。

https://ifconfig.me

authorize_security_group_ingress()でインバウンドルールの設定を行います。 引数には対象のセキュリティグループid、許可するポート、許可するIPアドレス(マイIP)、説明を指定します。

マイIPから設定した22番ポート(SSH)への接続を許可します。

5. サブネットグループの作成

RDSを起動するために、「2. プライベートサブネットの作成」で作成した2つプライベートサブネットをグループ化します。

# サブネットグループ作成メソッド
def __createSubnetGroup(self, subnet_id_list):
  # client のサービスをRDSに指定
  client = self.__awsConfig('rds')
  
  # サブネットグループの作成
  subnet_group = client.create_db_subnet_group(
    DBSubnetGroupName='rds-subnet-group', 
    DBSubnetGroupDescription='rds-subnet-group', 
    SubnetIds=subnet_id_list,
    Tags=[
      {'Key': 'Name', 'Value': 'test-rds-subnet-group'},
      {'Key': 'Owner', 'Value': '〓メールアドレス〓'}
    ]
  )
  
  #サブネットグループの名前を取得
  subnet_group_name = subnet_group['DBSubnetGroup']['DBSubnetGroupName']
  return subnet_group_name

create_db_subnet_group()でサブネットグループを作成します。引数には名前、説明、対象のサブネット(プライベートサブネット)のidのリスト、タグの名前、メールアドレスを指定します。

6. RDSインスタンスの作成

「2. プライベートサブネットの作成」で作成したプライベートサブネットにRDSインスタンス(データベース)を作成します。「5. サブネットグループの作成」で作成したサブネットグループ作成メソッドと、「4. EC2インスタンスの作成 」で使用したセキュリティグループ作成メソッドを使用します。

# データベース(RDS)の作成メソッド
def __createRds(self, subnet_id_list, vpc_id, ec2_security_group_id):
  # client のサービスをRDSに指定
  client = self.__awsConfig('rds')
  
  # サブネットグループメソッドの呼び出し
  subnet_group_name = self.__createSubnetGroup(subnet_id_list)
  
  # セキュリティグループ作成メソッドの呼び出し(RDS用を作成)
  security_group_id = self.__createSecurityGroup(vpc_id, 'test-rds-sg')
  
  # データベースの作成
  rds = client.create_db_instance(
    DBName='test_db',
    DBInstanceIdentifier='test-rds',
    DBInstanceClass='db.t2.micro',
    AllocatedStorage=20,
    Engine='mysql',
    MasterUsername='〓任意のマスターユーザー名〓',
    MasterUserPassword='〓任意のパスワード(8文字以上)〓',
    VpcSecurityGroupIds=[security_group_id],
    AvailabilityZone=self.availability_zone_1,
    DBSubnetGroupName=subnet_group_name,
    Port=3306,
    EngineVersion='8.0.27'
  )
  
  # RDS用セキュリティグループインバウンドルール設定メソッドの呼び出し
  inbound_rule = self.__settingRdsInboundRules(security_group_id, ec2_security_group_id, vpc_id)
  
  rds_name = rds['DBInstance']['DBInstanceIdentifier']
  return rds_name

まず、データベースで使用するRDS用のセキュリティグループを作成します。 EC2インスタンス作成時に使用した、セキュリティグループ作成メソッドを使用します。

create_db_instance()でデータベースを作成します。 引数にはデータベース名、DBインスタンス識別子、DBインスタンスクラス、ストレージ割り当てサイズ(GiB)、エンジン、マスターユーザー名、マスターユーザーのパスワード、作成したRDSのVPCセキュリティグループのid、アベイラビリティゾーン、サブネットグループ名、ポート、エンジンのバーションを指定します。

次に、作成したRDS用のセキュリティグループにインバウンドルールを設定します。# RDS用セキュリティグループインバウンドルール設定メソッド
def __settingRdsInboundRules(self, security_group_id, ec2_security_group_id, vpc_id):
  # client のサービスをEC2に指定
  client = self.__awsConfig('ec2')
  
  # インバウンドルールの作成
  inbound_rule = client.authorize_security_group_ingress(
    GroupId=security_group_id,
    IpPermissions=[
      {
        'FromPort': 3306,
        'IpProtocol': 'tcp',
        'ToPort': 3306,
        'UserIdGroupPairs': [
          {
            'Description': 'test rds inbound rule',
            'GroupId': ec2_security_group_id,
            'UserId': '〓AWSアカウントID〓',
            'VpcId': vpc_id
          }
        ]
      }
    ],
  )
  
  # セキュリティグループルール(インバウンドルール)idの取得
  inbound_rule_id = inbound_rule['SecurityGroupRules'][0]['SecurityGroupRuleId']
  
  # 作成したインバウンドルールにタグをつける
  tags = self.__createTags(client, inbound_rule_id, 'test-inbound-rule-rds')
  return inbound_rule

EC2インスタンス作成時に使用したセキュリティグループ作成と同様に、 authorize_security_group_ingress()を使用します。引数には作成したRDS用のセキュリティグループのid、ポート、プロトコル、説明、EC2インスタンスセキュリティグループのid、アカウントID、VPCのidを指定します。

RDS用のセキュリティグループでは、作成したEC2インスタンスからのみ接続を許可したいので、「UserIdGroupPairs」にEC2インスタンスのセキュリティグループのid、AWSアカウントID、VPCのidを指定する必要があります。

上記の指定することにより、インバウンドルールの「ソース」項目にセキュリティグループが指定され、指定したセキュリティグループを設定してあるEC2インスタンスからのみの接続を許可することができます。

これでインフラ構築自動化の準備が整いましたので、プログラムを実行し、実際にインスタンスなどが作成されているか検証を行います。

ソースコード全文は以下です。
※ファイル名を「create_aws_infra.py」としています。

# Boto3のインポート
import boto3
import requests


# インフラ環境作成クラス
class CreateAwsInfra():
  def __init__(self, access_key, secret_access_key):
    
    # インスタンス変数(アクセスキー・シークレットアクセスキー・リージョン・アベイラビリティゾーン)
    self.access_key = access_key
    self.secret_access_key = secret_access_key
    self.region_name = 'ap-northeast-1'
    self.availability_zone_1 = 'ap-northeast-1a'
    self.availability_zone_2 = 'ap-northeast-1c'
  
  
  # config(設定)メソッド
  def __awsConfig(self, service):
    # 引数で使用するサービスを指定、リージョン・アベイラビリティゾーンはインスタンス変数を指定
    client = boto3.client(
      service,
      aws_access_key_id = self.access_key,
      aws_secret_access_key = self.secret_access_key,
      region_name = self.region_name
    )
    return client
  
  
  # タグ作成メソッド
  def __createTags(self, client, id, name):
    # 指定したidの各サービスにNameタグ、Ownerタグをつける
    tags = client.create_tags(
      Resources=[id], 
      Tags=[
        {'Key': 'Name', 'Value': name},
        {'Key': 'Owner', 'Value': '〓メールアドレス〓'}
      ]
    )
    return tags
  
  
  # VPC作成メソッド
  def __createVpc(self):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # vpcの作成
    vpc = client.create_vpc(CidrBlock='10.0.0.0/16', InstanceTenancy='default')
    # vpcのidを取得
    id = vpc['Vpc']['VpcId']
    
    # 作成したVPCにタグをつける
    tags = self.__createTags(client, id, 'test-vpc')
    return id
  
  
  # サブネット作成メソッド
  def __createSubnet(self, vpc_id, availability_zone, cidr_block, name):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # サブネットの作成
    subnet = client.create_subnet(AvailabilityZone=availability_zone, CidrBlock=cidr_block, VpcId=vpc_id)
    # サブネットのidを取得
    id = subnet['Subnet']['SubnetId']
    
    # 作成したサブネットにタグをつける
    tags = self.__createTags(client, id, name)
    return id
  
  
  # インターネットゲートウェイ作成メソッド
  def __createInternetGateway(self, vpc_id):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    #インターネットゲートウェイの作成
    internet_gateway = client.create_internet_gateway()
    # インターネットゲートウェイのidを取得
    internet_gateway_id = internet_gateway['InternetGateway']['InternetGatewayId']
    
    # 作成したインターネットゲートウェイにタグをつける
    tags = self.__createTags(client, internet_gateway_id, 'test-igw')
    
    # インターネットゲートウェイをアタッチ
    attach = client.attach_internet_gateway(InternetGatewayId=internet_gateway_id, VpcId=vpc_id)
    return internet_gateway_id
  
  
  # ルートテーブル作成メソッド
  def __createRouteTable(self, vpc_id):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # ルートテーブルの作成
    route_table = client.create_route_table(VpcId=vpc_id)
    # ルートテーブルのidを取得
    id = route_table['RouteTable']['RouteTableId']
    
    # 作成したルートテーブルにタグをつける
    tags = self.__createTags(client, id, 'test-public-route-table')
    return id
  
  
  # カスタムルート作成メソッド
  def __createRoute(self, gateway_id, route_table_id, subnet_id):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # 作成したルートテーブルにカスタムルートを作成(送信先「0.0.0.0/0」)
    create_route = client.create_route(DestinationCidrBlock='0.0.0.0/0', GatewayId=gateway_id, RouteTableId=route_table_id)
    
    # サブネットの関連付け
    associate_route_subnet = client.associate_route_table(RouteTableId=route_table_id, SubnetId=subnet_id)
    
    # パブリックIPアドレスを自動的に受信するように設定
    attribute_subnet = client.modify_subnet_attribute(
      MapPublicIpOnLaunch={'Value': True},
      SubnetId=subnet_id
    )
    
    return create_route
  
  
  # プライベートサブネット作成メソッド
  def __createPrivateSubnet(self, vpc_id):
    availability_zone_list = [self.availability_zone_1, self.availability_zone_2]
    cidr_block_list = ['10.0.2.0/24', '10.0.20.0/24']
    name_list = ['private_subnet_1a', 'private_subnet_1c']
    subnet_id_list = []
    
    # アベイラビリティゾーン、CIDRブロックのリストをループさせ、作成したVPCにサブネットを作成
    for availability_zone, cidr_block, name in zip(availability_zone_list, cidr_block_list, name_list):
    
      # CIDRブロックが「10.0.2.0/24」「'10.0.20.0/24'」の2つのプライベートサブネットを作成
      subnet_id = self.__createSubnet(vpc_id, availability_zone, cidr_block, name)
      subnet_id_list.append(subnet_id)
    return subnet_id_list
  
  
  # パブリックサブネット作成メソッド
  def __createPublicSubnet(self, vpc_id):
    # サブネット作成メソッドの呼び出し(CIDRブロックが「10.0.1.0/24」のパブリックサブネットを作成)
    subnet_id = self.__createSubnet(vpc_id, self.availability_zone_1, '10.0.1.0/24', 'public_subnet_1a')
    
    # インターネットゲートウェイ作成メソッドの呼び出し
    internet_gateway_id = self.__createInternetGateway(vpc_id)
    
    # ルートテーブル作成メソッドの呼び出し
    route_table_id = self.__createRouteTable(vpc_id)
    
    # カスタムルート作成メソッドの呼び出し
    create_route = self.__createRoute(internet_gateway_id, route_table_id, subnet_id)
    return subnet_id
  
  
  # セキュリティグループ作成メソッド
  def __createSecurityGroup(self, vpc_id, name):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # セキュリティグループ作成
    security_group = client.create_security_group(Description=name, GroupName=name, VpcId=vpc_id)
    
    # 作成したセキュリティグループのidを取得
    security_group_id = security_group['GroupId']
    
    # 作成したセキュリティグループにタグをつける
    tags = self.__createTags(client, security_group_id, name)
    return security_group_id
  
  
  # インバウンドルール設定メソッド
  def __settingInboundRules(self, security_group_id, port):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # マイIP(現在のグローバルIPアドレス)を取得
    url = 'https://ifconfig.me'
    request = requests.get(url)
    ip_address = '{}/32'.format(request.text)
    
    # インバウンドルールの作成
    inbound_rule = client.authorize_security_group_ingress(
      GroupId=security_group_id,
      IpPermissions=[
        {
          'FromPort': port,
          'IpProtocol': 'tcp',
          'IpRanges': [
            {
              'CidrIp': ip_address,
              'Description': 'test inbound rule',
            },
          ],
          'ToPort': port
        }
      ]
    )
    
    # セキュリティグループルール(インバウンドルール)idの取得
    inbound_rule_id = inbound_rule['SecurityGroupRules'][0]['SecurityGroupRuleId']
    
    # 作成したインバウンドルールにタグをつける
    tags = self.__createTags(client, inbound_rule_id, 'test-inbound-rule-ssh')
    return inbound_rule
  
  
  # SSH用のキーペア作成メソッド
  def __createKeyPair(self):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # 鍵の名前
    key_name = 'test-key.pem'
    # キーペアの作成
    key = client.create_key_pair(KeyName=key_name)
    
    # キーペアidの取得
    key_pair_id = key['KeyPairId']
    
    # 作成したキーペアを取得し、pemファイルを作成
    key_material = key['KeyMaterial']
    with open(key_name, mode='w') as f:
      f.write(key_material)
    
    # 作成したキーペアにタグをつける
    tags = self.__createTags(client, key_pair_id, 'test-key-pair')
    return key_name
  
  
  # EC2インスタンス作成メソッド
  def __createInstance(self, subnet_id, vpc_id, security_group_name):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # セキュリティグループ作成メソッドの呼び出し
    security_group_id = self.__createSecurityGroup(vpc_id, security_group_name)
    
    # キーペア作成メソッドの呼び出し
    key_name = self.__createKeyPair()
    
    # パブリックIPアドレスの自動割り当ての有効
    valid_auto_public_ip = client.modify_subnet_attribute(
      MapPublicIpOnLaunch={'Value': True},
      SubnetId=subnet_id
    )
    
    # AMIは「Amazon Linux2」を使用
    ami_id = 'ami-04204a8960917fd92'
    
    # EC2インスタンス作成
    ec2_instance = client.run_instances(
      ImageId=ami_id, 
      MinCount=1, 
      MaxCount=1, 
      InstanceType="t2.micro", 
      SecurityGroupIds=[security_group_id], 
      KeyName=key_name, 
      SubnetId=subnet_id
    )
    
    # インスタンスidの取得
    instance_id = ec2_instance['Instances'][0]['InstanceId']
    
    # インバウンドルール設定メソッド呼び出し
    inbound_rule = self.__settingInboundRules(security_group_id, 22)
    
    # 作成したインスタンスにタグをつける
    tags = self.__createTags(client, instance_id, 'test-web-server')
    return instance_id, security_group_id
  
  
  # サブネットグループ作成メソッド
  def __createSubnetGroup(self, subnet_id_list):
    # client のサービスをRDSに指定
    client = self.__awsConfig('rds')
    
    # サブネットグループの作成
    subnet_group = client.create_db_subnet_group(
      DBSubnetGroupName='rds-subnet-group', 
      DBSubnetGroupDescription='rds-subnet-group', 
      SubnetIds=subnet_id_list,
      Tags=[
        {'Key': 'Name', 'Value': 'test-rds-subnet-group'},
        {'Key': 'Owner', 'Value': '〓メールアドレス〓'}
      ]
    )
    
    #サブネットグループの名前を取得
    subnet_group_name = subnet_group['DBSubnetGroup']['DBSubnetGroupName']
    return subnet_group_name
  
  
  # RDS用セキュリティグループインバウンドルール設定メソッド
  def __settingRdsInboundRules(self, security_group_id, ec2_security_group_id, vpc_id):
    # client のサービスをEC2に指定
    client = self.__awsConfig('ec2')
    
    # インバウンドルールの作成
    inbound_rule = client.authorize_security_group_ingress(
      GroupId=security_group_id,
      IpPermissions=[
        {
          'FromPort': 3306,
          'IpProtocol': 'tcp',
          'ToPort': 3306,
          'UserIdGroupPairs': [
            {
              'Description': 'test rds inbound rule',
              'GroupId': ec2_security_group_id,
              'UserId': '077698332591',
              'VpcId': vpc_id
            }
          ]
        }
      ],
    )
    
    # セキュリティグループルール(インバウンドルール)idの取得
    inbound_rule_id = inbound_rule['SecurityGroupRules'][0]['SecurityGroupRuleId']
    
    # 作成したインバウンドルールにタグをつける
    tags = self.__createTags(client, inbound_rule_id, 'test-inbound-rule-rds')
    return inbound_rule
  
  
  # データベース(RDS)の作成メソッド
  def __createRds(self, subnet_id_list, vpc_id, ec2_security_group_id):
    # client のサービスをRDSに指定
    client = self.__awsConfig('rds')
    
    # サブネットグループメソッドの呼び出し
    subnet_group_name = self.__createSubnetGroup(subnet_id_list)
    
    # セキュリティグループ作成メソッドの呼び出し(RDS用を作成)
    security_group_id = self.__createSecurityGroup(vpc_id, 'test-rds-sg')
    
    # データベースの作成
    rds = client.create_db_instance(
      DBName='test_db',
      DBInstanceIdentifier='test-rds',
      DBInstanceClass='db.t2.micro',
      AllocatedStorage=20,
      Engine='mysql',
      MasterUsername='〓任意のマスターユーザー名〓',
      MasterUserPassword='〓任意のパスワード(8文字以上)〓',
      VpcSecurityGroupIds=[security_group_id],
      AvailabilityZone=self.availability_zone_1,
      DBSubnetGroupName=subnet_group_name,
      Port=3306,
      EngineVersion='8.0.27'
    )
    
    # RDS用セキュリティグループインバウンドルール設定メソッドの呼び出し
    inbound_rule = self.__settingRdsInboundRules(security_group_id, ec2_security_group_id, vpc_id)
    
    rds_name = rds['DBInstance']['DBInstanceIdentifier']
    return rds_name


  # インフラ環境構築を自動化するメソッド
  def createInfra(self):
    # vpc作成
    vpc_id = self.__createVpc()
    print('VPCを作成しました。')
    
    # プライベートサブネット作成
    private_subnet_id_list = self.__createPrivateSubnet(vpc_id)
    print('プライベートサブネットを作成しました。')
    
    # パブリックサブネット作成
    public_subnet_id = self.__createPublicSubnet(vpc_id)
    print('パブリックサブネットを作成しました。')
    
    # EC2インスタンス作成
    instance = self.__createInstance(public_subnet_id , vpc_id, 'test-web-server-sg')
    print('EC2インスタンスを作成しました。')
    
    # EC2セキュリティグループidの取得
    ec2_security_group_id = instance[1]
    
    # RDSインスタンス作成(データベース作成)
    rds_instance = self.__createRds(private_subnet_id_list, vpc_id, ec2_security_group_id)
    print('RDSインスタンスを作成しました。')


if __name__ == '__main__':
  access_key = '〓アクセスキー〓'
  secret_access_key = '〓シークレットアクセスキー〓'
  aws = CreateAwsInfra(access_key, secret_access_key)
  create_infra = aws.createInfra()
  print('インフラ環境を構築しました。')

参考記事:
https://docs.aws.amazon.com/ja_jp/
autoscaling/ec2/APIReference/API_Operations.html
https://docs.aws.amazon.com/ja_jp/
AmazonRDS/latest/APIReference/API_Operations.html
https://docs.aws.amazon.com/ja_jp/
AmazonRDS/latest/UserGuide/Overview.RDSSecurityGroups.html#Overview.RDSSecurityGroups.Compare
https://boto3.amazonaws.com/v1/
documentation/api/latest/reference/services/ec2.html
https://boto3.amazonaws.com/v1/
documentation/api/latest/reference/services/rds.html

検証・結果

プログラムの実行結果は以下のようになります。

プログラムの実行結果

プログラムで作成が成功しているので、実際にインスタンスなどが作られているか、AWSコンソールにログインして確認してみましょう。

1. VPCの確認

VPCが作成されていることを確認できました。

VPCの確認

2. プライベートサブネットの確認

10.0.2.0/24、10.0.20.0/24のプライベートサブネットが作成されていることを確認できました。

プライベートサブネットの確認

3. パブリックサブネットの確認

10.0.1.0/24のパブリックサブネットが作成されていることを確認できました。

パブリックサブネットの確認

4. インターネットゲートウェイの確認

インターネットゲートウェイが作成されていることを確認できました。 

インターネットゲートウェイの確認

5. ルートテーブルの確認

ルートテーブルが作成されていることを確認できました。

ルートテーブルの確認

6. カスタムルートの確認

ルートテーブルの「サブネットの関連付け」タブに、作成したパブリックサブネットが関連付けられていることを確認できました。

カスタムルートの確認

7. セキュリティグループの確認

セキュリティグループと設定したインバウンドルールが作成されていることを確認できました。

セキュリティグループの確認

8. キーペアの確認 

キーペアが作成されていることを確認できました。

 キーペアの確認 

9. EC2インスタンスの確認 

EC2インスタンスが作成されていることを確認できました。 また、作成したVPC、サブネット、セキュリティグループが紐づいていること、パブリックIPアドレスが割り当てられていることも確認できました。

EC2インスタンスの確認 
EC2インスタンスの確認 

10. サブネットグループの確認 

サブネットグループが作成され、プライベートサブネットがグループ化されていることを確認できました。

サブネットグループの確認 

11. RDS用のセキュリティグループの確認 

RDS用のセキュリティグループが作成され、設定したインバウンドルールが反映されていることを確認できました。

RDS用のセキュリティグループの確認

12. RDSインスタンスの確認 

RDSインスタンスが作成され、作成したセキュリティグループのインバウンドルールが設定されていることを確認できました。

RDSインスタンスの確認
RDSインスタンスの確認

Boto3で作成した全てのサービスが作成されていることを確認できました。

AWS Cloudformationによる自動化ついて

AWSを使った業務自動化においては、AWS Cloudformationが人気の高いサービスです。Cloudformationは、プロビジョニングやサーバー設定を自動化することができるソリューションで、現場の負担削減に役立ちます。

このサービスの特徴は、頻繁に使用するAWS環境をテンプレート化し、新たに構築した環境にそのまま適用することができる点です。何度も同じ設定を手動で行う必要がなくなるので、現場でのルーティンワークの排除や、ヒューマンエラーによる設定ミスの解消などに貢献します。

インフラ環境構築の自動化に際しては、こちらの導入も検討してみましょう。

終わりに

おわりに

今回は、PythonとBoto3を使用してAWSのインフラ構築を自動化する方法を紹介いたしました。 AWSのインフラ構築自動化は、業務効率化やケアレスミスの回避においては重要な取り組みです。Boto3を使用してインフラ環境構築を自動化してみたい、と思う方はぜひ参考にしてみてください。

また、Boto3で作成するのにとても時間がかかりましたが、Boto3で何ができるのかが分かり、さらにはコンソール上で作成していた時にはあまり理解できていなかった部分を、Boto3で作成することにより理解することができたので、自分にとってとてもためになりました。

AWSにはCloudFormationというサービスがあるので、次はそちらを使用して構築の自動化をしてみたいなと思いました。なお、自社によるAWSの導入や設計、運用が難しいという企業様は、お気軽にご相談ください。ネットワーク構成の設計、サーバの設計、スクリプトの設計から構築、運用監視までご対応させていただきます。

最後までお読みいただきありがとうございました。

人気の記事

最新情報をお届けします!

最新のITトレンドやセキュリティ対策の情報を、メルマガでいち早く受け取りませんか?ぜひご登録ください

メルマガ登録