Skip to content

Instantly share code, notes, and snippets.

@shgeta
Last active August 29, 2015 14:23
Show Gist options
  • Save shgeta/4206ccf43cd987215e0d to your computer and use it in GitHub Desktop.
Save shgeta/4206ccf43cd987215e0d to your computer and use it in GitHub Desktop.
[aws] [shell] 手作業で作ったaws ec2を shell script でcloudformationに落とす。(移設やバックアップの補助スクリプト)

手作業で作ったaws ec2を shell script でcloudformationに落とす。

概要

単一vpc内のオブジェクトをcloudformationテンプレートに落とし込むものです。 コピペで動かします。

aws の cloudformationは一度作ってしまえば、別のvpcにでも別のアカウントにでも、簡単に同じ構成が再現できてとても便利。 なんだけど、作るのがとてもめんどくさい。 現物 to cloudformation のコンバートスクリプトを作っていく。 「決まりごと」によってスクリプトを簡単にできるなら「決まりごと」で対応していこうとおもう。 mac osxでしか動かしていない。

使える場面

  • もちろん単純にバックアップ。
  • ドキュメント化するのがめんどくさい時にとりあえずお茶を濁す。
  • 開発と本番設置が完全に分かれていて、本番設置を人に頼まなくてはいけないような時。

決まりごと(予定)

  • Name をcloudformation の論理名命名規則に従う。大文字で始まるキャメルケース。
  • Nameは絶対に入れる。
  • Nameはvpc内でかぶらないようにする。(InstanceNamae,SubnetNamae,SgNamae などと頭にタイプをつけるとかぶりにくい。)
  • Nameに通し番号をつける場合は最後に直接つける。0でパディングしたりしない。(例 InstanceNamae1 , InstanceNamae2 などとする。)
  • グローバルに繋がる部分は手動でやる。グローバルIP,ELB,SourceDestCheck 等 (危険防止)
  • Noneという文字列は使わない。
  • [Instance] ローカルIpアドレスを複数持たさない。

共通の仕様

  • 単一vpcのコンバートとする
  • Name はcloudformation の論理名命名規則に準拠しておくと出来上がったcloudformationテンプレートが読みやすい。準拠していない場合は適当に処理される。
  • 対象とする vpcId は BENRI_AWS_TARGET_VPC_ID を見る。export しておく。
  • タグに aws:cloudformation:logical-id が入っていたら、そちらを優先して cloudformation 論理名としてつかう。<廃止するかも。
  • [Instance] ローカルIpアドレスを複数持つもたない

予定

  • サブネット
  • セキュリティーグループ
  • ルーティングと関連付け(インスタンス向けを含まない)
  • インスタンス
  • ルーティングと関連付け(インスタンス向け)
  • まるっと一発で全部

依存関係

出来上がったテンプレートには上下関係があります。
たとえば、サブネットがなくてはインスタンスができないと言ったような。

以下に順序を示す

サブネット セキュリティーグループ <どちらが先でもよろしい
ルーティングと関連付け(インスタンス向けを含まない)
インスタンス
ルーティングと関連付け(インスタンス向け)


パッと使えるawsコマンド集について

コマンド集の決まり

  • コピペで貼り付けて動かす。
  • できるだけPOSIXに近づけよう!(できるだけね。POSIX準拠しか使えない人が改造する時に楽にしよう)

[パッと使えるawsコマンド集] vpc内のセキュリティーグループをcloudformationテンプレートに落とす。

使い方

export BENRI_AWS_TARGET_VPC_ID=vpc-xxxxxxxx

などとしてBENRI_AWS_TARGET_VPC_IDにvpc_idを設定しておきます。 複数のアカウントをまたがって作業している場合は、

export AWS_DEFAULT_PROFILE='profile_name' 

などとして操作すると便利です。(詳細は調べてください。) スクリプトのコードをコピーします。 ターミナルに貼り付けます。 結果が出力されます。

勘弁してもらうこと

  • 他アカウントのセキュリティーグループは考慮しない予定。
  • Name以外のタグは考慮しない

仕様

  • defaultのセキュリティーグループの扱いが未定 暫定で対象外とする。

TODO

  • outputsの整備

備考

  • コマンドの実行だけではvpc内に何かを作ったりしません。安心して回せます。とりあえず回してみて
スクリプト
{
 (
 
 
 
{
  #init
    _kinshi_moji_for_logical_name="_-.;:+*/[]()@# "
  # (

  _script_id="routetableassociationtocf"
  _cloud_formation_template_description="Security Group"
  
  
  _file_tmp_files=$(mktemp -t "$_script_id")
  _file_output=$(mktemp -t "$_script_id")
  echo "$_file_output" >>"$_file_tmp_files"
  
  
  _file_output_params=$(mktemp -t "$_script_id")
  echo "$_file_output_params" >>"$_file_tmp_files"
  _file_output_resources=$(mktemp -t "$_script_id")
  echo "$_file_output_resources" >>"$_file_tmp_files"
  _file_output_outputs=$(mktemp -t "$_script_id")
  echo "$_file_output_outputs" >>"$_file_tmp_files"
  
  _file_output_security_groups=$(mktemp -t "$_script_id")
  echo "$_file_output_security_groups" >>"$_file_tmp_files"
  _delimiter_file_output_security_groups=""
  
  _file_security_groups=$(mktemp -t "$_script_id")
  echo "$_file_security_groups" >>"$_file_tmp_files"

  _file_security_group_ingress_ip=$(mktemp -t "$_script_id")
  echo "$_file_security_group_ingress_ip" >>"$_file_tmp_files"
  _file_security_group_ingress_sg=$(mktemp -t "$_script_id")
  echo "$_file_security_group_ingress_sg" >>"$_file_tmp_files"

  _file_security_group_egress_ip=$(mktemp -t "$_script_id")
  echo "$_file_security_group_egress_ip" >>"$_file_tmp_files"
  _file_security_group_egress_sg=$(mktemp -t "$_script_id")
  echo "$_file_security_group_egress_sg" >>"$_file_tmp_files"
  
  _file_tmp_permissions_per_sg_id=$(mktemp -t "$_script_id")
  echo "$_file_tmp_permissions_per_sg_id" >>"$_file_tmp_files"

  aws ec2  "describe-security-groups" --query "*[]|[?VpcId==\`$BENRI_AWS_TARGET_VPC_ID\`]|[].[GroupId,GroupName,Tags[?Key==\`Name\`].Value|[0] ,Tags[?Key==\`aws:cloudformation:logical-id\`].Value|[0] ,Description]" --output text |  sort -k 2 >"$_file_security_groups"

  aws ec2  "describe-security-groups" --query "*[]|[?VpcId==\`$BENRI_AWS_TARGET_VPC_ID\`]|[?length(IpPermissions[? length(IpRanges) != \`0\`])!= \`0\`].[ \`securitygroup\`  ,GroupId , GroupName ,Tags[?Key==\`Name\`].Value|[0] ,Tags[?Key==\`aws:cloudformation:logical-id\`].Value|[0] , length(IpPermissions[?length(IpRanges) != \`0\`]) , IpPermissions[?length(IpRanges) != \`0\`][ \`ippermissions\` , ToPort,IpProtocol,FromPort,IpRanges[].CidrIp] ]" --output text >"$_file_security_group_ingress_ip"

  aws ec2  "describe-security-groups" --query "*[]|[?VpcId==\`$BENRI_AWS_TARGET_VPC_ID\`]|[?length(IpPermissions[? length(UserIdGroupPairs) != \`0\`])!= \`0\`].[ \`securitygroup\`  ,GroupId, GroupName ,Tags[?Key==\`Name\`].Value|[0] ,Tags[?Key==\`aws:cloudformation:logical-id\`].Value|[0] , length(IpPermissions[?length(UserIdGroupPairs) != \`0\`]) , IpPermissions[][ \`ippermissions\` , ToPort,IpProtocol,FromPort , UserIdGroupPairs[][join(\`:\`,*)] |[] |[] ] ]" --output text >"$_file_security_group_ingress_sg"

  aws ec2  "describe-security-groups" --query "*[]|[?VpcId==\`$BENRI_AWS_TARGET_VPC_ID\`]|[?length(IpPermissionsEgress[? length(IpRanges) != \`0\`])!= \`0\`].[ \`securitygroup\`  ,GroupId , GroupName ,Tags[?Key==\`Name\`].Value|[0] ,Tags[?Key==\`aws:cloudformation:logical-id\`].Value|[0] , length(IpPermissionsEgress[?length(IpRanges) != \`0\`]) , IpPermissionsEgress[?length(IpRanges) != \`0\`][ \`ippermissionsegress\` , ToPort,IpProtocol,FromPort,IpRanges[].CidrIp] ]" --output text >"$_file_security_group_egress_ip" 

  aws ec2  "describe-security-groups" --query "*[]|[?VpcId==\`$BENRI_AWS_TARGET_VPC_ID\`]|[?length(IpPermissionsEgress[? length(UserIdGroupPairs) != \`0\`])!= \`0\`].[ \`securitygroup\`  ,GroupId, GroupName ,Tags[?Key==\`Name\`].Value|[0] ,Tags[?Key==\`aws:cloudformation:logical-id\`].Value|[0] , length(IpPermissionsEgress[?length(UserIdGroupPairs) != \`0\`]) , IpPermissionsEgress[][ \`ippermissionsegress\` , ToPort,IpProtocol,FromPort,UserIdGroupPairs[][join(\`:\`,*)] |[] |[] ] ]" --output text >"$_file_security_group_egress_sg"


  cat $(cat $_file_tmp_files)
  
  
  # cat "$_file_security_groups"
  # 
  
  function set_security_group_data ()
  {
        _security_group_data=$(cat "$_file_security_groups" | grep "$_security_group_id")
        # echo "$_security_group_data"
        _group_name=$(echo "$_security_group_data" | cut -f2) 
        _security_group_name=$(echo "$_security_group_data" | cut -f3)        
        if test "$_security_group_name" == "None"
          then
          _security_group_name="created-from-$(echo $_security_group_id| tr -d '-')"
        fi
        _security_group_logical_name=$(echo "$_security_group_data" | cut -f4)
        if test "$_security_group_logical_name" == "None"
          then
          _security_group_logical_name=$(echo "Sg$_security_group_name"| tr -d "$_kinshi_moji_for_logical_name")
        fi
        _security_group_description=$(echo "$_security_group_data" | cut -f5)
  }
}


{
  #面倒でも複数回回す。
  #先ずは本体を作る
  echo "sg base"
  for _security_group_id in $(cat "$_file_security_groups"|cut -f1)
  do
  

    
    set_security_group_data
    if test "$_group_name" == "default"
      then
      echo "exclude default $_security_group_id"
      continue
    fi
  
  # _file_output_security_group_egress_to_cidr_per_group=
  # _file_output_security_group_ingress_to_cidr_per_group=
  
    echo "$_delimiter_file_output_security_groups" >>"$_file_output_security_groups"
cat >>"$_file_output_security_groups" <<EOF
    "$_security_group_logical_name": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "VpcId": {
          "Ref": "VpcId"
        },
        "GroupDescription": "$_security_group_description",
        "Tags": [{
          "Key": "Name",
          "Value": "$_security_group_name"
        }],
        "SecurityGroupIngress": [],
        "SecurityGroupEgress": [{
          "IpProtocol": "-1",
          "FromPort": -1,
          "ToPort": -1,
          "CidrIp": {
            "Ref": "AmazonDnsCidr"
          }
        }
        ]
      }
    }
EOF

    _delimiter_file_output_security_groups=","
  
  done
  
}



{
  #ingressを作っていく
  echo "ingress"
  echo "  ip"
  _file_target="$_file_security_group_ingress_ip"
  cat /dev/null >"$_file_tmp_permissions_per_sg_id"
    for _security_group_id in $(cat "$_file_target" |grep "^securitygroup" | cut -f2)
    do
      _security_group_head=$(cat "$_file_target"| grep "^securitygroup" | grep "$_security_group_id")
      echo "$_security_group_head"
      _group_name=$(echo "$_security_group_head" | cut -f3) 
      if test "$_group_name" == "default"
        then
        echo "exclude default $_security_group_id"
        continue
      fi
      
      _permission_count=$(echo "$_security_group_head" | cut -f6)
      echo "count $_permission_count"
      _rows_size=$(expr "$_permission_count" "*" 2)
      cat "$_file_target" | grep "$_security_group_id" -A $_rows_size |sed -e '1,1d' >"$_file_tmp_permissions_per_sg_id" 


#copipe
    set_security_group_data

      (
      while read _line
        do
        if test $(echo "$_line" | cut -f1) == "ippermissions"
          then
                        _from=$(echo "$_line" | cut -f4)
                        if test "$_from" == "None"
                          then
                          _from=-1
                        fi
                        _to=$(echo "$_line" | cut -f2)
                        if test "$_to" == "None"
                          then
                          _to=-1
                        fi
                        _proto=$(echo "$_line" | cut -f3)
          continue
        fi
        
        for _cidr in $_line
        do
          echo $_cidr
          _this_logical_name=$(echo "${_security_group_logical_name}Ingress${_from}${_proto}${_to}To${_cidr}" | tr -d "$_kinshi_moji_for_logical_name") 
          
          echo "$_delimiter_file_output_security_groups" >>"$_file_output_security_groups" 
cat >>"$_file_output_security_groups" <<EOF
    "$_this_logical_name": {
      "Type": "AWS::EC2::SecurityGroupIngress",
      "Properties": {
        "GroupId": {
          "Ref": "$_security_group_logical_name"
        },
        "IpProtocol": "$_proto",
        "FromPort": $_from,
        "ToPort": $_to,
        "CidrIp": "$_cidr"
      }
    }
EOF
          _delimiter_file_output_security_groups=","
        done
        
        _from=
        _to=
        _proto=
        done <"$_file_tmp_permissions_per_sg_id" 
      
      )
      
      
      
    done
}






{
  # テスト用
  # _delimiter_file_output_security_groups=","
  #sg ingress
    echo "  sg"
    _file_target="$_file_security_group_ingress_sg"
    cat /dev/null >"$_file_tmp_permissions_per_sg_id"
    for _security_group_id in $(cat "$_file_target" |grep "^securitygroup" |cut -f2)
    do
      echo "start of $_file_target"
      echo $_security_group_id
      _security_group_head=$(cat "$_file_target"| grep "^securitygroup" | grep "$_security_group_id")
      echo "_security_group_head"
      echo "$_security_group_head"
      _group_name=$(echo "$_security_group_head" | cut -f3) 
      if test "$_group_name" == "default"
        then
          echo "exclude default $_security_group_id"
          continue
      fi
      _permission_count=$(echo "$_security_group_head" | cut -f6)
      echo "count $_permission_count"
      _rows_size=$(expr "$_permission_count" "*" 2)
      cat "$_file_target" |grep -e "^securitygroup\s$_security_group_id" -A $_rows_size |sed -e '1,1d' >"$_file_tmp_permissions_per_sg_id" 

      cat "$_file_tmp_permissions_per_sg_id"      
      # #チェック本来不要
      if test $(cat "$_file_tmp_permissions_per_sg_id" | wc -l ) -ne "$_rows_size"
        then
          echo "ERROR _rows_size not match _file_tmp_permissions_per_sg_id size." 
          exit
      fi
#copipe
      set_security_group_data
      if test "$_group_name" == "default"
        then
        echo "exclude default $_security_group_id"
        continue
      fi
            (
            while read _line
              do
              if test $(echo "$_line" | cut -f1) == "ippermissions"
                then
                        _from=$(echo "$_line" | cut -f4)
                        if test "$_from" == "None"
                          then
                          _from=-1
                        fi
                        _to=$(echo "$_line" | cut -f2)
                        if test "$_to" == "None"
                          then
                          _to=-1
                        fi
                        _proto=$(echo "$_line" | cut -f3)
                        
                continue
              fi
              
              for _uidandsgid in $_line
              do
                # echo $_uidandsgid
                _to_from_sg_id=$(echo "$_uidandsgid" | cut -f2 -d":")
                
                # echo "_koko_start_"
                # echo $_security_group_logical_name
                # echo $_to_from_sg_id
                _to_from_security_group_logical_name=$( (_security_group_id="$_to_from_sg_id" ; set_security_group_data ;echo "$_security_group_logical_name" ))
                # echo $_security_group_logical_name
                # echo $_to_from_security_group_logical_name
                # echo "_koko_end_"
                
                _this_logical_name=$(echo "${_security_group_logical_name}Ingress${_from}${_proto}${_to}To${_uidandsgid}" | tr -d "$_kinshi_moji_for_logical_name") 
                # echo "$_delimiter_file_output_security_groups"
                echo "ingress $_proto:($_from - $_to) from $_to_from_security_group_logical_name"
                echo "$_delimiter_file_output_security_groups" >>"$_file_output_security_groups" 
cat >>"$_file_output_security_groups" <<EOF
    "$_this_logical_name": {
      "Type": "AWS::EC2::SecurityGroupIngress",
      "Properties": {
        "GroupId": {
          "Ref": "$_security_group_logical_name"
        },
        "IpProtocol": "$_proto",
        "FromPort": $_from,
        "ToPort": $_to,
        "SourceSecurityGroupId": {
          "Ref": "$_to_from_security_group_logical_name"
        }
      }
    }
EOF
                _delimiter_file_output_security_groups=","
              
              done
              # echo "$_delimiter_file_output_security_groups"
              _from=
              _to=
              _proto=
              done <"$_file_tmp_permissions_per_sg_id" 
            # echo "$_delimiter_file_output_security_groups"
            )
#       
#       
    done
    
    # cat $_file_output_security_groups
}


{
  #egressを作っていく
  echo "egress"
  echo "  ip"
  _file_target="$_file_security_group_egress_ip"
  cat /dev/null >"$_file_tmp_permissions_per_sg_id"
    for _security_group_id in $(cat "$_file_target" |grep "^securitygroup" | cut -f2)
    do
      _security_group_head=$(cat "$_file_target"| grep "^securitygroup" | grep "$_security_group_id")
      echo "$_security_group_head"
      _group_name=$(echo "$_security_group_head" | cut -f3) 
      if test "$_group_name" == "default"
        then
        echo "exclude default $_security_group_id"
        continue
      fi
      
      _permission_count=$(echo "$_security_group_head" | cut -f6)
      # echo "count $_permission_count"
      _rows_size=$(expr "$_permission_count" "*" 2)
      cat "$_file_target" | grep "$_security_group_id" -A $_rows_size |sed -e '1,1d' >"$_file_tmp_permissions_per_sg_id" 

      echo "---"
      cat "$_file_tmp_permissions_per_sg_id" 
      echo "..."
      # #チェック本来不要
      if test $(cat "$_file_tmp_permissions_per_sg_id" | wc -l ) -ne "$_rows_size"
        then
          echo "ERROR _rows_size not match _file_tmp_permissions_per_sg_id size." 
          exit
      fi
#copipe
      set_security_group_data

      (
      while read _line
        do
        if test $(echo "$_line" | cut -f1) == "ippermissionsegress"
          then
                        _from=$(echo "$_line" | cut -f4)
                        if test "$_from" == "None"
                          then
                          _from=-1
                        fi
                        _to=$(echo "$_line" | cut -f2)
                        if test "$_to" == "None"
                          then
                          _to=-1
                        fi
                        _proto=$(echo "$_line" | cut -f3)
          continue
        fi
        
        for _cidr in $_line
        do
          # echo $_cidr
          _this_logical_name=$(echo "${_security_group_logical_name}Egress${_from}${_proto}${_to}To${_cidr}" | tr -d "$_kinshi_moji_for_logical_name") 
          
          echo "ingress $_proto:($_from - $_to) from $_cidr"
          
          
          echo "$_delimiter_file_output_security_groups" >>"$_file_output_security_groups" 
cat >>"$_file_output_security_groups" <<EOF
    "$_this_logical_name": {
      "Type": "AWS::EC2::SecurityGroupEgress",
      "Properties": {
        "GroupId": {
          "Ref": "$_security_group_logical_name"
        },
        "IpProtocol": "$_proto",
        "FromPort": $_from,
        "ToPort": $_to,
        "CidrIp": "$_cidr"
      }
    }
EOF
          _delimiter_file_output_security_groups=","
        done
        
        _from=
        _to=
        _proto=
        done <"$_file_tmp_permissions_per_sg_id" 
      
      )
      
      
      
    done
    #テスト用
    #  cat $_file_output_security_groups
}


{
  # テスト用
  # _delimiter_file_output_security_groups=","
  #sg egress
    echo "  sg"
    _file_target="$_file_security_group_egress_sg"
    cat /dev/null >"$_file_tmp_permissions_per_sg_id"
    for _security_group_id in $(cat "$_file_target" |grep "^securitygroup" |cut -f2)
    do
      echo "start of $_file_target"
      echo $_security_group_id
      _security_group_head=$(cat "$_file_target"| grep "^securitygroup" | grep "$_security_group_id")
      echo "_security_group_head"
      echo "$_security_group_head"
      _group_name=$(echo "$_security_group_head" | cut -f3) 
      if test "$_group_name" == "default"
        then
          echo "exclude default $_security_group_id"
          continue
      fi
      _permission_count=$(echo "$_security_group_head" | cut -f6)
      # echo "count $_permission_count"
      _rows_size=$(expr "$_permission_count" "*" 2)
      cat "$_file_target" |grep -e "^securitygroup\s$_security_group_id" -A $_rows_size |sed -e '1,1d' >"$_file_tmp_permissions_per_sg_id" 

      cat "$_file_tmp_permissions_per_sg_id"      
      # #チェック本来不要
      if test $(cat "$_file_tmp_permissions_per_sg_id" | wc -l ) -ne "$_rows_size"
        then
          echo "ERROR _rows_size not match _file_tmp_permissions_per_sg_id size." 
          exit
      fi
#copipe
      set_security_group_data
      if test "$_group_name" == "default"
        then
        echo "exclude default $_security_group_id"
        continue
      fi
            (
            while read _line
              do
              if test $(echo "$_line" | cut -f1) == "ippermissionsegress"
                then
                        _from=$(echo "$_line" | cut -f4)
                        if test "$_from" == "None"
                          then
                          _from=-1
                        fi
                        _to=$(echo "$_line" | cut -f2)
                        if test "$_to" == "None"
                          then
                          _to=-1
                        fi
                        _proto=$(echo "$_line" | cut -f3)
                        
                continue
              fi
              
              for _uidandsgid in $_line
              do
                # echo $_uidandsgid
                _to_from_sg_id=$(echo "$_uidandsgid" | cut -f2 -d":")
                
                # echo "_koko_start_"
                # echo $_security_group_logical_name
                # echo $_to_from_sg_id
                _to_from_security_group_logical_name=$( (_security_group_id="$_to_from_sg_id" ; set_security_group_data ;echo "$_security_group_logical_name" ))
                # echo $_security_group_logical_name
                # echo $_to_from_security_group_logical_name
                # echo "_koko_end_"
                
                _this_logical_name=$(echo "${_security_group_logical_name}Egress${_from}${_proto}${_to}To${_uidandsgid}" | tr -d "$_kinshi_moji_for_logical_name") 
                # echo "$_delimiter_file_output_security_groups"
                echo "egress $_proto:($_from - $_to) to $_to_from_security_group_logical_name"
                echo "$_delimiter_file_output_security_groups" >>"$_file_output_security_groups" 
cat >>"$_file_output_security_groups" <<EOF
    "$_this_logical_name": {
      "Type": "AWS::EC2::SecurityGroupEgress",
      "Properties": {
        "GroupId": {
          "Ref": "$_security_group_logical_name"
        },
        "IpProtocol": "$_proto",
        "FromPort": $_from,
        "ToPort": $_to,
        "DestinationSecurityGroupId": {
          "Ref": "$_to_from_security_group_logical_name"
        }
      }
    }
EOF
                _delimiter_file_output_security_groups=","
              
              done
              # echo "$_delimiter_file_output_security_groups"
              _from=
              _to=
              _proto=
              done <"$_file_tmp_permissions_per_sg_id" 
            # echo "$_delimiter_file_output_security_groups"
            )
#       
#       
    done
    
    #  cat $_file_output_security_groups
}


#self test
{
(
# test1
_expect=$(aws ec2  "describe-security-groups" --query "*[]|[?VpcId==\`$BENRI_AWS_TARGET_VPC_ID\`]|[?GroupName!=\`default\`].[GroupId,GroupName,Tags[?Key==\`Name\`].Value|[0] ,Tags[?Key==\`aws:cloudformation:logical-id\`].Value|[0] ,Description]" --output text | wc -l)
_actual=$(cat "$_file_output_security_groups" |grep '"AWS::EC2::SecurityGroup"' -c)
if test "$_actual" -ne "$_expect"
  then
  echo "ERROR :: テンプレート中のSGの数がおかしい。expect=$_expect actual=$_actual" >&2
  exit 1
fi

)


}



{  
cat "$_file_output_security_groups" >"$_file_output_resources"
  
cat  >"$_file_output" <<EOF
{
  "Description": "$_cloud_formation_template_description",
  "Parameters": {
        "VpcId": {
          "Type": "AWS::EC2::VPC::Id",
          "Description": "VpcId of your existing Virtual Private Cloud (VPC)."
        },
        "AmazonDnsCidr" : {
          "Type": "String",
          "Description": "Amazon Dns Ip cidr. (ex. 192.168.0.2/32)",
          "Default": "192.168.0.2/32"
        }
    $(cat "$_file_output_params")

  },
  "Resources": {
    $(cat "$_file_output_resources")
  },
  "Outputs": {
    $(cat "$_file_output_outputs")
  }
}
EOF
  
  _fsize=$(wc -c <"$_file_output")
  
  if test  "$_fsize" -gt 51200
    then 
    cat "$_file_output"
    echo "テンプレートのサイズが大きいので、自分でs3にアップしてaws cloudformation validate-template --template-url コマンドで検査してください。" >&2
    exit
  else
    cat "$_file_output"
    aws cloudformation validate-template --output table  --template-body "$(cat $_file_output)"
  fi
  echo "..."

  # rm $(echo $(cat "$_file_tmp_files") )
  if test -z "$BENRI_AWS_TARGET_VPC_ID"
    then
      echo "ERROR :: please set BENRI_AWS_TARGET_VPC_ID"
  fi
  # )

}
)
}



[パッと使えるawsコマンド集] vpc内のサブネットをcloudformationテンプレートに落とす。

前提条件

  • 前提条件awscliが使えること。

使い方

export BENRI_AWS_TARGET_VPC_ID=vpc-xxxxxxxx

などとしてBENRI_AWS_TARGET_VPC_IDにvpc_idを設定しておきます。 複数のアカウントをまたがって作業している場合は、

export AWS_DEFAULT_PROFILE='profile_name' 

などとして操作すると便利です。(詳細は調べてください。) スクリプトのコードをコピーします。 ターミナルに貼り付けます。 結果が出力されます。

勘弁してもらうこと

  • 論理名がNoneという文字列である場合を考慮しない。
  • AvailabilityZoneは名前ちょく書き。リージョンが変わる場合は適当に置換。
  • サブネット名にはあまり記号など入っていないこと希望。
  • サブネット名が入っていなければサブネットIDを代わりに使う。

備考

  • コマンドの実行だけではvpc内に何かを作ったりしません。安心して回せます。とりあえず回してみて大丈夫!
スクリプト
{
(
    _file_tmp_files=$(mktemp -t subnettocf)
    _file_output=$(mktemp -t subnettocf)
    echo $_file_output >>"$_file_tmp_files"
        
    (
    _file_subnets=$(mktemp -t subnettocf)
    echo $_file_subnets >>"$_file_tmp_files"
    
    _file_created_subnets=$(mktemp -t subnettocf)
    echo $_file_created_subnets >>"$_file_tmp_files"
    
    _file_output_subnets_params=$(mktemp -t subnettocf)
    echo $_file_output_subnets_params >>"$_file_tmp_files"
    _file_output_subnets=$(mktemp -t subnettocf)
    echo $_file_output_subnets >>"$_file_tmp_files"  
    _file_output_subnet_outputs=$(mktemp -t subnettocf)
    echo "$_file_output_subnet_outputs" >>"$_file_tmp_files"  

    
    
    aws ec2  "describe-subnets" --query "*[]|[?VpcId==\`$BENRI_AWS_TARGET_VPC_ID\`]|[].[SubnetId , CidrBlock , Tags[?Key==\`Name\`].Value|[0] , Tags[?Key==\`aws:cloudformation:logical-id\`].Value|[0] , AvailabilityZone]" --output text|  sort -k 2 >"$_file_subnets"

    
    #Resources部を作ります
    _delimiter=""
    for _subnet_id in $(cat "$_file_subnets" | cut -f1)
    do
      _subnet_data=$(cat "$_file_subnets"| grep "$_subnet_id")
      _subnet_name=$(echo "$_subnet_data" | cut -f3)
      if test "$_subnet_name" == "None"
        then
        _subnet_name="created-from-$(echo $_subnet_id| tr -d '-')"
      fi
      _subnet_logical_name=$(echo "$_subnet_data" | cut -f4)
      if test "$_subnet_logical_name" == "None"
        then
        _subnet_logical_name="$(echo $_subnet_name| tr -d '_-.;:+*/[]()@# ')"
      fi
      _subnet_az_name=$(echo "$_subnet_data" | cut -f5)
      _subnet_cidr=$(echo "$_subnet_data" | cut -f2)
      
      echo "$_delimiter" >>"$_file_output_subnets"
      
cat >>"$_file_output_subnets" <<EOF
    "$_subnet_logical_name": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "AvailabilityZone": "$_subnet_az_name",
        "CidrBlock": "$_subnet_cidr",
        "Tags": [{
          "Key": "Name",
          "Value": "$_subnet_name"
        }],
        "VpcId": {
          "Ref": "VpcId"
        }
      }
    }
EOF
cat >>"$_file_created_subnets" <<EOF
$_subnet_logical_name $_subnet_cidr
EOF
      _delimiter="    ,"
    done
    
    
    
    #Outputs部を作ります
    _delimiter=""
    for _subnet_logical_name in $(cat "$_file_created_subnets" | cut -d" " -f1)
    do
      echo "$_delimiter" >>"$_file_output_subnet_outputs"

cat >>"$_file_output_subnet_outputs" <<EOF
    "$_subnet_logical_name": { 
      "Value": {
        "Ref": "$_subnet_logical_name"
      },
      "Description": "$_subnet_logical_name"
    }
EOF
      
      
      _delimiter="    ,"
    done
    # cat "$_file_output_subnet_outputs"
    
    
cat >"$_file_output" <<EOF
{
  "Description": "Subnets",
  "Parameters": {
        "VpcId": {
          "Type": "AWS::EC2::VPC::Id",
          "Description": "VpcId of your existing Virtual Private Cloud (VPC)."

        }
  },
  "Resources": {
    $(cat "$_file_output_subnets")
  },
  "Outputs": {
    $(cat "$_file_output_subnet_outputs")
  }
}
EOF

)
    _fsize=$(wc -c <$_file_output)
    if test  $_fsize -gt 51200
      then 
      echo "---"
      cat $_file_output
      echo "..."
      echo "テンプレートのサイズが大きいので、自分でs3にアップしてaws cloudformation validate-template --output table  --template-url コマンドで検査してください。" >&2
       
    else
      echo "---"
      cat "$_file_output" 
      echo "..."
      aws cloudformation validate-template --output table  --template-body "$(cat $_file_output)" 
      
      
    fi

    rm $(echo $(cat "$_file_tmp_files") )
    
    )
  }
出力
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment