Terraform備忘録

雑メモ

# HCL syntax

ref https://www.terraform.io/docs/configuration/syntax.html

## リソース

```
resource "<リースの種類>" "<リソース名>" {}
```

- リソースの種類は、プロバイダーがAWSの場合はaws_*という名前でTerraformで予め定義されています。VPCであればaws_vpc、EC2であればaws_instance
- リソース名は任意の名前を設定可能

## 参照

```
<リソースの種類>.<リソース名>.<属性名>
```


## Map

```
variable "images" {
    default = {
        us-east-1 = "ami-1ecae776"
        us-west-2 = "ami-e7527ed7"
        us-west-1 = "ami-d114f295"
        eu-west-1 = "ami-a10897d6"
        eu-central-1 = "ami-a8221fb5"
        ap-southeast-1 = "ami-68d8e93a"
        ap-southeast-2 = "ami-fd9cecc7"
        ap-northeast-1 = "ami-cbf90ecb"
        sa-east-1 = "ami-b52890a8"
    }
}
```

## List

TODO

## 変数

Terraformでは、変数はvariableブロックで定義する

```
変数の定義
variable "<変数名>" {}
```

## Output

terraformした時に結果が見れる

```
// output "<アウトプットする属性の説明>" { value = "<アウトプットする属性値>"}
output "public ip of cm-test" {
  value = "${aws_instance.cm-test.public_ip}"
}
```

# Terraform Workspace

```
> terraform workspace list 
* default
  staging
> terraform workspace select staging 
Switched to workspace "staging".
> terraform workspace list
  default
* staging
> terraform workspace show 
staging

$ terraform console
> terraform.workspace
staging
>

```


# Subnet

今回の構成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/94686/fa74fb5c-45a3-d9e1-e324-0130d07dcc21.png)
https://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-nat-gateway.html

## Subnet構成
- public
  - public サブネットには、public ip アドレスを付与し、VPCの外からも見えるネットワークを作ります。 ELBを配置します。 また、nat-privateへの踏み台サーバーを建てる
- nat-private
  - 外部ネットワークからアクセスは行えず、外のネットワークへ出る際に、nat を通るネットワーク おもに、自分で作ったアプリケーション（Railsアプリとか）を配置
- private
  - 外部ネットワークからアクセスは行えず、外のネットワークに出る必要のないネットワーク Database等のdatastoreを配置

なお、subnetはそれぞれAZごとに作る。 東京リージョンでは aとcとAZがあるので、2つ作る


## TFファイル

cidrsubnet

```
resource "aws_subnet" "public1a" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 0)}"
  availability_zone = "ap-northeast-1a"

  tags {
    Name    = "${var.service}-${var.envname}-public1a"
  }
}

resource "aws_subnet" "public1c" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 1)}"
  availability_zone = "ap-northeast-1c"

  tags {
    Name    = "${var.service}-${var.envname}-public1c"
  }
}

resource "aws_subnet" "nat-private1a" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 4)}"
  availability_zone = "ap-northeast-1a"

  tags {
    Name    = "${var.service}-${var.envname}-nat-private1a"
  }
}

resource "aws_subnet" "nat-private1c" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 5)}"
  availability_zone = "ap-northeast-1c"

  tags {
    Name    = "${var.service}-${var.envname}-nat-private1c"
  }
}

resource "aws_subnet" "private1a" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 2)}"
  availability_zone = "ap-northeast-1a"

  tags {
    Name    = "${var.service}-${var.envname}-private1a"
  }
}

resource "aws_subnet" "private1c" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 3)}"
  availability_zone = "ap-northeast-1c"

  tags {
    Name    = "${var.service}-${var.envname}-private1c"
  }
}
```

cidrsubnetの計算

```
> cidrsubnet("172.20.0.0/16", 3, 0)
172.20.0.0/19 //  00000000
> cidrsubnet("172.20.0.0/16", 3, 1)
172.20.32.0/19 // 00100000
> cidrsubnet("172.20.0.0/16", 3, 2)
172.20.64.0/19 // 01000000
> cidrsubnet("172.20.0.0/16", 3, 3)
172.20.96.0/19 // 01100000
...
> cidrsubnet("172.20.0.0/16", 3, 7) # 3つ目のブロックの3ビット分を7(111)で埋めるので、11100000(224)
172.20.224.0/19
> cidrsubnet("172.20.0.0/16", 3, 8) // 8は２進数で4桁(1000)なのでエラー
cidrsubnet: prefix extension of 3 does not accommodate a subnet numbered 8 in:
```

ref
https://note.cman.jp/network/subnetmask.cgi
https://hogehoge.tk/tool/number.html

### IPv4プライベートアドレス範囲（RFC1918）：
10.0.0.0〜10.255.255.255（24ビットブロック）
172.16.0.0〜172.31.255.255（20ビットブロック）
192.168.0.0〜192.168.255.255（16ビットブロック）

ref http://itdoc.hitachi.co.jp/manuals/3021/3021324220/NNMS0200.HTM

## subnet のネットワーク

subnet内でのネットワークの流れを定義する必要があります。 どうやって外と通信するか。という感じ

public subnetでは、internet gateway を用意します。
これはVPCとしてのネットワークの出入り口でもあります。

nat-private subnetでは nat_gateway というものを用意します。
これは実態としてはEC2インスタンス（だとおもう）で、public ipアドレスを付与する必要があります。 以前は、AWSが用意したnat用のAMIを自身で起動して用意していましたが、nat_gatewayというマネージドなnatが利用できるようになりました。

```
resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.vpc.id}"

  tags {
    Name    = "${var.service}_${var.envname}_gateway"
  }
}

resource "aws_eip" "nat_gateway" {
  vpc = true
}

resource "aws_nat_gateway" "nat_gw" {
  allocation_id = "${aws_eip.nat_gateway.id}"
  subnet_id     = "${aws_subnet.public1a.id}"
  depends_on    = ["aws_internet_gateway.gw"]
}
```

ルートテーブル
実際の、subnetのルーティングを設定します。 0.0.0.0/0 、つまりすべてのネットワークをgatewayに流していく

```
resource "aws_route_table" "public" {
  vpc_id = "${aws_vpc.vpc.id}"

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags {
    Name    = "${var.service}_${var.envname}_public"
  }
}

resource "aws_route_table" "nat-private" {
  vpc_id = "${aws_vpc.vpc.id}"

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = "${aws_nat_gateway.nat_gw.id}"
  }

  tags {
    Name    = "${var.service}_${var.envname}_nat-private"
  }
}
```

ルートテーブルを作っただけではダメで、それをどのsubnetで使うかを設定

```
resource "aws_route_table_association" "public1a" {
  route_table_id = "${aws_route_table.public.id}"
  subnet_id      = "${aws_subnet.public1a.id}"
}

resource "aws_route_table_association" "public1c" {
  route_table_id = "${aws_route_table.public.id}"
  subnet_id      = "${aws_subnet.public1c.id}"
}

resource "aws_route_table_association" "nat-private1a" {
  route_table_id = "${aws_route_table.nat-private.id}"
  subnet_id      = "${aws_subnet.nat-private1a.id}"
}

resource "aws_route_table_association" "nat-private1c" {
  route_table_id = "${aws_route_table.nat-private.id}"
  subnet_id      = "${aws_subnet.nat-private1c.id}"
}
```


## セキュリティーグループ

```
aws_security_group.tf
resource "aws_security_group" "allow_all" {
    vpc_id = "${aws_vpc.vpc-1.id}"
    name = "allow_all" // AWS 上の実際のセキュリティグループ名称
    ingress { //  inbound 側のセキュリティ指定
        from_port = 80 // 開始ポート
        to_port = 80 // 終了ポート
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"] // 許可する CIDR
    }
    egress {//  outbound 側のセキュリティ指定
        from_port = 0
        to_port = 0 
        protocol = "-1" // 1にすると全トラフィック。
        cidr_blocks = ["0.0.0.0/0"]  // 許可するアドレスの範囲
    }
    description = "test"
}
```

### Load balancer 

Network Load Balancer(NLB) : L4 NATロードバランサ
Application Load Balancer(ALB) : L7リバースプロキシ
Classic Load Balancer(CLB) : L4/L7リバースプロキシ

リソース | 用途
---|---
aws_lb	| LBの作成
aws_lb_target_group | ターゲットグループの作成
aws_lb_target_group_attachment | ターゲットグループとインスタンスまたはコンテナとひも付け
aws_lb_listener | リスナーの作成(とALBとターゲットグループのひも付け)
aws_lb_listener_rule | リスナーのルール作成

```
クライアント <-> リスナー <-> ターゲット
```

```
resource "aws_lb" "alb" {
  name                       = "${var.name}"
  security_groups            = ["${aws_security_group.alb.id}"]  // ALBに紐付けるセキュリティグループの配列
  subnets                    = ["${aws_subnet.frontend_subnet.*.id}"] // ALBに紐付けるサブネットIDの配列
  internal                   = false // true であればInternal ALBに
  enable_deletion_protection = false
  load_balancer_type         = "application"

  access_logs {
    bucket = "${aws_s3_bucket.alb_log.bucket}"
  }
}

resource "aws_lb_target_group" "alb" {
  count    = 2
  name     = "${var.name}-tg${count.index+1}"
  port     = 80
  protocol = "HTTP"
  vpc_id   = "${aws_vpc.vpc.id}"
 
  health_check { // ヘルスチェック
    interval            = 30
    path                = "/index.html"
    port                = 80
    protocol            = "HTTP"
    timeout             = 5
    unhealthy_threshold = 2
    matcher             = 200
  }
  // スティッキーセッションの設定もある
}

resource "aws_lb_listener" "alb" {
  load_balancer_arn = "${aws_alb.alb.arn}" // ALBのARN
  port              = "443" // ALBが待ち受けるポート番号
  protocol          = "HTTPS" // クライアントからALBへのアクセス時に利用されるプロトコル
  ssl_policy        = "ELBSecurityPolicy-2015-05" // クライアンとALB間での通信に利用されるSSLポリシー
  certificate_arn   = "${var.alb_config["certificate_arn"]}"  // (AWS上の)SSL証明書のARN
 
  default_action { // リスナーのデフォルトアクション
    target_group_arn = "${aws_alb_target_group.alb.0.arn}" // ターゲットグループのARN。 このターゲットグループにトラフィックが流れる
    type             = "forward" // トラフィックの流し方
  }
}
```



### ARN構文

```
arn:partition:service:region:account-id:resource
```


### ECS

![image.png](https://qiita-image-store.s3.amazonaws.com/0/94686/949be43a-89c9-b409-231a-5302d8edd6f1.png)


用語について

用語 | 解説
---|---
Task Definitions | コンテナの集合を定義。必ず同じインスタンスになる ≒ docker-compose
Task | Task Definitionsが実体化されたもの、リソースの余裕のあるContainer Instanceで実行される
Container | Taskの実態であるDocker Containers、Container Instance上で動く
Container Instance | ContainerのホストとなるAmazon EC2、DockerとAgentが動いている
Agent | Amazon ECSのエンドポイントと通信するエージェント
Cluster | Container Instanceの集合体
Serivce |  Web APIのような長期的なワークロードに最適、Taskを必要数保つスケジューラー
Run Task | バッチジョブのような短期的なワークロードに最適、Task Definitionsにしていしたタスクを実行する

ref https://www.slideshare.net/AmazonWebServicesJapan/20150727-jaws-container1-ecspublic

AWS Moduleのリソースについて

リソース | 用途
---|---
aws_ecs_cluster	| LBの作成
aws_ecs_task_definition | ターゲットグループの作成
template_file | ターゲットグループとインスタンスまたはコンテナとひも付け


```
```

## 権限

### IAMユーザーとIAMロールとIAMグループ

### ポリシー

ポリシーは基本的に、「誰が」「どのAWSサービスの」「どのリソースに対して」「どんな操作を」「許可する(許可しない)」、といったことをJSON形式で記述します。
記述したポリシーをユーザー(IAMユーザー、IAMグループ、IAMロール)や、AWSリソースに関連づけることで、アクセス制御を実現しています。


# references

- https://astap.hatenablog.jp/entry/2017/06/13/124708
- https://int128.hatenablog.com/entry/2018/06/28/180504
- https://dev.classmethod.jp/cloud/terraform-getting-started-with-aws/
- https://qiita.com/zembutsu/items/5de875ed99ac8a56a998
- https://dev.classmethod.jp/cloud/aws/describe-elb-types/
- https://dev.classmethod.jp/cloud/aws/ecs-alb-routing/
- https://christina04.hatenablog.com/entry/2018/02/09/095743
- https://dev.classmethod.jp/cloud/aws/terraform-alb/
- https://www.slideshare.net/AmazonWebServicesJapan/20150727-jaws-container1-ecspublic
- https://dev.classmethod.jp/cloud/aws-iam-policy/