Memo/Terraform/aws

https://dexlab.net:443/pukiwiki/index.php?Memo/Terraform/aws
 

AWS


Lambda


CloudFront?


WAF


policy jsonの代わりに aws_iam_policy_document を使う

terraformのドキュメントの例には「policy = <json>」のように書いてある部分もあるが、毎回差分が出る不具合があるので、aws_iam_policy_documentを使うと良さそう。

  • s3.tf: exampleバケットに対して、Webhosting用のPublic Read、IP制限をする場合
    resource "aws_s3_bucket_policy" "example" {
        bucket = "${aws_s3_bucket.example.id}"
        policy = "${data.aws_iam_policy_document.s3_example_public_read.json}"
    }
    
    data "aws_iam_policy_document" "s3_example_public_read" {
      statement {
        sid = "IPAllow"
        effect = "Allow"
    
        principals {
          type = "*"
          identifiers = ["*"]
        }
    
        actions = [
          "s3:GetObject",
        ]
    
        resources = [
          "arn:aws:s3:::example/*",
        ]
    
        condition {
          test     = "IpAddress"
          variable = "aws:SourceIp"
          values = [
            "192.0.2.0/24",   # TEST-NET-1
            "198.51.100.0/24",# TEST-NET-2
            "203.0.113.0/24", # TEST-NET-3
          ]
        }
      }
    }

既存EC2にIAM roleを付けたい

  • 環境
    • Terraform v0.10.7
  • iam_instance_profileを付けて、terraform applyしても反映されない。
  • aws cliのassociate-iam-instance-profile だと可能
    aws ec2 associate-iam-instance-profile \
    --instance-id i-123456 \
    --iam-instance-profile "Name=example-role" \
    --profile example
    }

セキュリティグループルールはaws_security_group_ruleを使う

ルールの追加は「aws_security_group_rule」推奨。 aws_security_groupに書くとplan時に順番が変わって、diffとして表示されてしまう。


No valid credential sources found for AWS Provider.

  • チェックポイント
    • terraformは「~/.aws/credentials」内のkeyしか読まない。このファイル内にクレデンシャルが必要。ansibleは「~/.aws/config」にkeyがあれば読んでくれるので誤解する。
      cat ~/.aws/credentials
      [myprofile]
      aws_access_key_id = AK****
      aws_secret_access_key = ****
    • ちょっとしたフォーマットの違い(ダブルクオートの有無、スペースの有無等)で読めていない。一度セクションを消して、awsコマンドで生成する。
      aws configure --profile myprofile

tfファイル内で複数AWSアカウント、複数リージョンを扱う

  • tfファイルで、異なるリージョンを扱う。デフォルトproviderは必須のようで、存在しないとエラーになる(terraform v0.10.2)
    variable "aws_profile" {} # awscli profile name. terraform plan/apply時にプロンプトを出す
    provider "aws" {
      profile = "${var.aws_profile}"
      region  = "ap-northeast-1" # tokyo
    }
    
    provider "aws" {
      profile = "${var.aws_profile}"
      region  = "us-east-1"
      alias   = "us-east-1"
    }
    
    resource "aws_s3_bucket" "tokyo-example" {
      bucket = "tokyo.example.com"
      acl = "private"
    }
    
    resource "aws_s3_bucket" "us-east-1-example" {
      provider = "aws.us-east-1"
      bucket = "us-east-1.example.com"
      acl = "private"
    }
  • 作成済みリソースを terraform importする場合
    terraform import aws_s3_bucket.tokyo-example tokyo.example.com
    terraform import -provider=aws.us-east-1 aws_s3_bucket.us-east-1-example virginia.example.com

VPC Peering

  • 異なるAWSアカウント間で、VPC peeringを設定する
    • アクセプタ側でVPC > ピア接続 > 選択 > アクション > 許可する
    • 手動で許可する場合、terraform applyが必ず失敗する(auto_accept = false でも)。許可した後、もう一度実行が必要
  • aws.tf
    variable "aws_region" { default = "ap-northeast-1" }
    // リクエスタ側のAWS account情報. aws configure --profile <name> で設定しておく
    variable "main_aws_profile" {}
    variable "main_aws_vpc_id" { default = "vpc-aaaaa" }
    variable "main_aws_route_table_id" { default = "rtb-11111111" }
    variable "main_aws_cidr" { default = "172.31.0.0/16" }
    provider "aws" {
      profile = "${var.main_aws_profile}"
      region  = "${var.aws_region}"
    }
    
    // "${data.aws_caller_identity.main.account_id}" として参照可能
    data "aws_caller_identity" "main" {
    }
    
    // アクセプタ側のAWS account情報
    variable "peer_aws_account_id" { default = "2222222222" }
    variable "peer_vpc_id" { default = "vpc-bbbbb" }
    variable "peer_vpc_cidr" { default = "10.5.0.0/16" }
  • iam.tf
    output "aws_iam_role.vpc_peering.arn"     { value = "${aws_iam_role.vpc_peering.arn}" }
    resource "aws_iam_role" "vpc_peering" {
        name               = "main-vpcpeering"
        assume_role_policy = "${data.aws_iam_policy_document.sts-assumerole.json}"
    }
    
    # AWS console上だとIAM > ロール > ロール名 > 信頼関係タブの部分
    data "aws_iam_policy_document" "sts-assumerole" {
      statement {
        actions = [
          "sts:AssumeRole",
        ]
        effect = "Allow"
        principals = {
          type = "AWS"
          identifiers = [
            "arn:aws:iam::${var.peer_aws_account_id}:root",
          ]
        }
      }
    }
    
    # AWS console上だとIAM > ロール > ロール名 > アクセス許可タブ > インラインポリシーの部分
    resource "aws_iam_role_policy" "vpc_peering" {
        name   = "main-vpcpeering"
        role   = "${aws_iam_role.vpc_peering.id}"
        policy = "${data.template_file.vpc_peering.rendered}"
    }
    
    data "template_file" "vpc_peering" {
      template = "${file("./policy/vpc-peering-connection.tpl")}"
    
      vars {
        aws_region          = "${var.aws_region}"
        main_aws_account_id = "${data.aws_caller_identity.main.account_id}"
        main_aws_vpc_id     = "${var.main_aws_vpc_id}"
        peer_aws_account_id = "${var.peer_aws_account_id}"
        peer_aws_vpc_id     = "${var.peer_vpc_id}"
      }
    }
  • ./policy/vpc-peering-connection.tpl
    {
       "Version":"2012-10-17",
       "Statement":[
          {
             "Effect":"Allow",
             "Action":"ec2:AcceptVpcPeeringConnection",
             "Resource":"arn:aws:ec2:${aws_region}:${main_aws_account_id}:vpc-peering-connection/*",
             "Condition":{
                "ArnEquals":{
                   "ec2:RequesterVpc":"arn:aws:ec2:${aws_region}:${peer_aws_account_id}:vpc/${peer_aws_vpc_id}"
                }
             }
          },
          {
             "Effect":"Allow",
             "Action":"ec2:AcceptVpcPeeringConnection",
             "Resource":"arn:aws:ec2:${aws_region}:${main_aws_account_id}:vpc/${main_aws_vpc_id}"
          }
       ]
    }
  • vpc_peering.tf
    // Requester's side of the connection.
    // https://www.terraform.io/docs/providers/aws/r/vpc_peering.html
    resource "aws_vpc_peering_connection" "main" {
      vpc_id        = "${var.main_aws_vpc_id}"
      peer_vpc_id   = "${var.peer_vpc_id}"
      peer_owner_id = "${var.peer_aws_account_id}"
      auto_accept   = false
    
      tags {
        Name = "VPC Peering between main and peer"
        Side = "Requester"
      }
    }
    
    resource "aws_route" "main" {
      route_table_id            = "${var.main_aws_route_table_id}"
      destination_cidr_block    = "${var.peer_vpc_cidr}"
      vpc_peering_connection_id = "${aws_vpc_peering_connection.main.id}"
    }
  • アクセプタ側のAWSアカウントも自分で管理している時
    variable "peer_aws_route_table_id" { default = "rtb-22222" }
    // Accepter's credentials.
    
    provider "aws" {
      alias = "peer"
      profile = "peer" // aws configure --profile <name> で設定しておく
      region = "ap-northeast-1"
    }
    
    // Accepter's side of the connection.
    // https://www.terraform.io/docs/providers/aws/r/vpc_peering_accepter.html
    resource "aws_vpc_peering_connection_accepter" "peer" {
      provider                  = "aws.peer"
      vpc_peering_connection_id = "${aws_vpc_peering_connection.main.id}"
      auto_accept               = true
    
      tags {
        Name = "VPC Peering between main and peer"
        Side = "Accepter"
      }
    }
    
    resource "aws_route" "peer" {
      provider                  = "aws.peer"
      route_table_id            = "${var.peer_aws_route_table_id}"
      destination_cidr_block    = "${var.main_aws_cidr}"
      vpc_peering_connection_id = "${aws_vpc_peering_connection_accepter.peer.id}"
    }

AWS account_id/arn/user_idの取得

// "${data.aws_caller_identity.main.account_id}" として参照できる
data "aws_caller_identity" "main" {}

EC2起動時にuser_dataを渡す

  • ec2.tf
    resource "aws_instance" "web01" {
    ...
      user_data = "${file("cloud-config.yaml")}"
    ...
    }

セキュリティグループを後から変更しようとするとEC2を作り直してしまう

  • VPCの場合、security_groups ではなく vpc_security_group_ids を使う

aws_nat_gateway

  • subnet毎にnat-gatewayを作成
  • terraform v0.10.0
    variable aws_subnets {
      type = "list"
      default = [
        "subnet-aaaa",  # AZ: ap-northeast-1a
        "subnet-cccc",  # AZ: ap-northeast-1c
      ]
    }
    
    resource "aws_nat_gateway" "gw" {
      allocation_id = "${aws_eip.gw.*.id[count.index]}"
      subnet_id     = "${var.aws_subnets[count.index]}"
      count         = "${length(var.aws_subnets)}"
    }
    
    resource "aws_eip" "gw" {
      vpc   = true
      count = "${length(var.aws_subnets)}"
    }

複数リソースの指定

  • EC2の数がsubnet数を超えても、AZが正しく振られるようにする
variable "ec2_subnets" { default = ["subnet-xxxx","subnet-xxxx","subnet-xxxx"] }

resource "aws_instance" "web" {
...
  count     = 4
  subnet_id = "${var.ec2_subnets[count.index % length(var.ec2_subnets)]}"
}
  • 変数と配列を指定 v0.10.2
    variable "cidr_common" { default = "192.168.2.1/32" }
    variable "cidr_example" { default = ["192.168.1.0/24", "10.5.1.0/24"] }
    
    resource "aws_security_group" "common" {
    ...
      cidr_blocks = [
        "${var.cidr_common}",
        "${var.cidr_example}"
      ]
  • EC2インスタンスにEIPを付ける v0.10.2
    variable "instance_count_web"       { default = 1 }
    
    # aws_elbは複数リソースがそのまま指定できる
    resource "aws_elb" "frontend" {
        instances = ["${aws_instance.web.*.id}"]
    }
    
    # aws_eipは一つのリソースしか指定できないので変換して渡す
    resource "aws_eip" "web" {
        count = "${var.instance_count_web}"
        instance = "${element(aws_instance.web.*.id, count.index)}"
        vpc = true
    }
  • Resource '〜' not found for variable '〜.1.id': 「.0.id」はアクセスできるが、「.1.id」がエラーになった。terraformの不具合か分からないが、以下の様に明示的に指定できる
    "${element(aws_instance.web.*.id, 1)}"

RDS

AWS: aws_db_instance - Terraform by HashiCorp

  • classic network上にRDSを作る場合にsubnetのエラーが出る。v0.8.6で確認
    • 「publicly_accessible = true」が必要

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-10-12 (金) 17:00:48 (36d)