Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@masa3521

github actionsを使って aws + terraform + ansible でCI/CD環境を構築してみた

概要

最近github actionsが楽しいのでaws環境でteraform + ansible実行してみた。
EC2を構築し、httpdをインストールする所まで実施。

目次

・事前準備
・ディレクトリ構成
・バケット作成
・IAMユーザ作成
・terraformコード作成
・ansible コード作成
・github actions 作成
・githu actions 実行結果

事前準備

  • EC2のIPの自動取得にdyanamic inventoryが使用できること

ディレクトリ構成

├── README.md
├── ansible
│   ├── ansible.cfg
│   ├── ec2.ini
│   ├── ec2.py
│   ├── roles
│   │   ├── common
│   │   │   ├── files
│   │   │   │   └── main.yml
│   │   │   └── tasks
│   │   └── nginx
│   │       ├── files
│   │       └── tasks
│   │           └── main.yml
│   ├── sandbox.yml
└── terraform
    ├── backend.tf
    ├── data.tf
    ├── main.tf
    ├── output
    ├── output.tf
    ├── provider.tf
    └── variables.tf

S3バケット作成

tfstate保存用のバケットを作成する。

バケット作成
% aws s3 mb s3://tf-sandbox-masa3521
make_bucket: tf-sandbox-masa3521

IAMユーザ作成

terraform,ansibleの実行用のIAMユーザを作成する。
EC2とS3、key系はパラメータストアから取得するので必要な権限を付与する。

IAMユーザ作成
% aws iam create-user --user-name cicd_user

{
    "User": {
        "Path": "/",
        "UserName": "cicd_user",
        "UserId": "***************",
        "Arn": "arn:aws:iam::***************:user/cicd_user",
        "CreateDate": "2020-05-21T15:05:18Z"
    }
}
アクセスキー付与
% aws iam create-access-key --user-name cicd_user
{
    "AccessKey": {
        "UserName": "cicd_user",
        "AccessKeyId": "***************",
        "Status": "Active",
        "SecretAccessKey": "***************",
        "CreateDate": "2020-05-22T00:42:37Z"
    }
}
権限付与〜policy確認
% aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess  --user-name cicd_user
% aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess --user-name cicd_user
% aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess --user-name cicd_user
% aws iam list-attached-user-policies --user-name cicd_user
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonEC2FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonEC2FullAccess"
        },
        {
            "PolicyName": "AmazonS3FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonS3FullAccess"
        },
        {
            "PolicyName": "AmazonSSMReadOnlyAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess"
        }
    ]
}

key作成

EC2に設定する公開鍵/秘密鍵を作成し、作成したものをパラメータストアに登録する。

key作成
% ssh-keygen -t rsa -b 4096  
parameter_storeに登録
% aws ssm put-parameter --name "publickey" \
                      --type SecureString \
                      --value  "$(cat id_rsa.pub)"

{
    "Version": 1,
    "Tier": "Standard"
}

% aws ssm put-parameter --name "pravatekey" \
                      --type SecureString \
                      --value  "$(cat id_rsa)"

{
    "Version": 1,
    "Tier": "Standard"
}

terraformコード作成

  • data.tfで公開鍵をパラメータストアから取得
  • backend.tfでtfstateをリモートで管理
  • output.tfでセキュリティーグループのgroupidをファイルに出力 ※後のgithub-actionsで使用
provider.tf
provider "aws" {
  profile = "default"
  version = "= 2.61"
  region  = "ap-northeast-1"
}
backend.tf
terraform {
  backend "s3" {
    bucket  = "tf-sandbox-masa3521"
    region  = "ap-northeast-1"
    key     = "terraform.tfstate"
    encrypt = true
  }
}
data.tf
data "aws_ssm_parameter" "publickey" {
  name            = "publickey"
  with_decryption = true
}
variables.tf
variable "region" {
  default = "ap-northeast-1"
}

variable "system" {
  default = "sandbox"
}
output.tf
resource "local_file" "sgroupid" {
  filename = "./group_id"
  content  = aws_security_group.sandboxSG.id
}
main.tf

resource "aws_vpc" "sandboxVPC" {
  cidr_block           = "10.1.0.0/16"
  instance_tenancy     = "default"
  enable_dns_support   = "true"
  enable_dns_hostnames = "false"
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_route_table" "sanbboxRT" {
  vpc_id = aws_vpc.sandboxVPC.id

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

  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_subnet" "sandboxSUBNET" {
  vpc_id     = aws_vpc.sandboxVPC.id
  cidr_block = "10.1.0.0/24"
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_internet_gateway" "sandboxGW" {
  vpc_id = aws_vpc.sandboxVPC.id
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_route_table_association" "sandboxRTA" {
  subnet_id      = aws_subnet.sandboxSUBNET.id
  route_table_id = aws_route_table.sanbboxRT.id
}

resource "aws_security_group" "sandboxSG" {
  name        = "sandboxSG"
  description = "Allow SSH inbound traffic"
  vpc_id      = aws_vpc.sandboxVPC.id
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_key_pair" "publickey" {
  key_name   = "key"
  public_key = data.aws_ssm_parameter.publickey.value
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_instance" "sandboxinstance" {
  key_name      = aws_key_pair.publickey.id
  ami           = "ami-0f310fced6141e627"
  instance_type = "t2.nano"
  vpc_security_group_ids = [
    aws_security_group.sandboxSG.id
  ]

  subnet_id                   = aws_subnet.sandboxSUBNET.id
  associate_public_ip_address = "true"
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

ansible 作成

ansile.cfg
[defaults]
deprecation_warnings = False
remote_user = ec2-user
private_key_file = ./privatekey
host_key_checking = False
sandbox.yml
- hosts: tag_Name_sandbox
  roles:
    - htted
roles/tasks/main.yml
---
- name: install apache
  yum:
   name: httpd
   state: present
  become: true
- name: Start httpd
  service:
    name: httpd
    state: started
    enabled: yes
  become: true

github-actions作成

  • 実行の為にsecretsの登録が必要
  • IPを自動で取得するためDynamic Inventoryで取得する。
  • ansble実行の為秘密鍵のダウンロード
  • ansible実行前にセキュリティーグループに自分のIPを登録、実行後に自分のIPを削除

secrets登録

スクリーンショット 2020-05-29 1.59.30.png

terraform-ansible.yml

name: Terraform deploy to Azure

on:
  push:
    branches:    
      - master

jobs:
  terraform-ansible:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1
      with:
        terraform_version: 0.12.9

    - name: Terraform Init
      run: terraform init
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform select
      run: terraform workspace select dev
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform Format
      run: terraform fmt -check
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform Plan
      run: terraform plan
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform Apply
      if: github.ref == 'refs/heads/master' && github.event_name == 'push'
      run: terraform apply -auto-approve
      working-directory: ${{ github.workspace }}/terraform

    - name: Set up Python 3.7
      uses: actions/setup-python@v2
      with:
        python-version: 3.7

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install boto ansible==2.9.2

    - name: Download privatekey
      run: aws ssm get-parameter --name "privatekey" --with-decryption | jq -r .Parameter.Value > ./privatekey
      working-directory: ${{ github.workspace }}/ansible

    - name: modify permission privatekey
      run: chmod 400 ./privatekey
      working-directory: ${{ github.workspace }}/ansible

    - name: open sg
      run:  aws ec2 authorize-security-group-ingress --group-id "$(cat ../terraform/group_id)" --protocol tcp --port 22 --cidr `curl inet-ip.info`/32
      working-directory: ${{ github.workspace }}/ansible

    - name: exec ansible
      run: ansible-playbook -i ec2.py sandbox.yml
      working-directory: ${{ github.workspace }}/ansible

    - name: close sg
      run:  aws ec2 revoke-security-group-ingress --group-id "$(cat ../terraform/group_id)" --protocol tcp --port 22 --cidr `curl inet-ip.info`/32
      working-directory: ${{ github.workspace }}/ansible

github-actions 結果

スクリーンショット 2020-05-29 2.07.50.png

[参考]
https://www.terraform.io/docs/github-actions/setup-terraform.html
https://github.com/aws-actions/configure-aws-credentials
https://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html

2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
masa3521
オンプレやりたく無いインフラエンジニアです。 主に仕事でAWS、プライベートでGCP使っています。 2020年1月よりAzureを使うこととなりました。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?