mito’s blog

IT技術メインの雑記。思い立ったが吉日。

自社のアドベントカレンダーを企画し、無事に完遂した話

はじめに

終わってみれば、ご協力もあり無事に完遂しましたが、社内(特に他部署と)の交流不足が大きかったと思います。
他部署でちらほらブログを書いていた方が数名いたので何とかなるでしょと思っていましたが、そもそも会話したことがないという状況でした。完全に勢いのみで開催しました。


準備

アドベントカレンダーについての詳細をGoogleドキュメントにまとめ、社内に公開しました。

  • アドベントカレンダーとは
  • アドベントカレンダーを開催する理由
    • 「社外にアウトプットする人が増えたら良いな、外から見た弊社が格好よくうつるんじゃないか」と、アウトプットする人を増やすいい機会だと思ったからです。
    • アウトプットは良いぞ
  • 投稿までの流れ
  • 投稿内容のご相談
    • ○○番煎じとか需要とか気にしないでいいです、毎年同じ内容の雑誌も出てますなどと話しました
  • 社内外へのPRとして私がすること
    • 投稿だけじゃなくツイートもします


周知

slackでどーんと告知した後、上司や他部署の役職者にも相談しました。
順序逆のほうがやりやすかったかもしれないけど、謎の強制力が働くので(気持ち的に)難しいところがあります。


記事一覧

並べてみると、投稿があった分野は多岐にわたっていました。

日付 タイトル
12/1 [AWS Backup] バックアップとリストアを試してみた - mito’s blog
12/2 [Ansible x Terraform] TerraformでKeyPairの作成やAmazon Secrets ManagerにKeyPairを登録し、Ansibleで利用する - mito’s blog
12/3 今の時代だからこそ、アニメーションで伝えよう
12/4 VSCode + Docusaurus で最高のドキュメント作成環境を構築する
12/5 いつの間にかRaspberry Pi Imagerが更に便利になっていました
12/6 Docusaurus で作成するドキュメントはココがいいね!
12/7 Nginx + Docusaurus でドキュメントをコンテナ化してみる
12/8 LaravelとReactでWebSocketを使ったブロードキャストアプリを作ってみる - Qiita
12/9 OpenAPIGeneratorの自動生成におけるコントローラーの生成単位はURLで決まる
12/10 Nginx + OAuth2 Proxy で静的 Web サイトに認証機能を追加してみる
12/11 静的 Web サイトに認証をつけて AWS App Runner でデプロイしてみる
12/12 SwiftUI でサイズクラスに対応する - Qiita
12/13 IndexedDBの概念がわかりづらい件について - Qiita
12/14 Cloud9でseleniumを動かしてみた - Qiita
12/15 seleniumをコンテナ化して動かしてみた - Qiita
12/16 Google Cloud Next '22に参加してクラウドエンジニアの育成について考えた - Qiita
12/17 ML Kit Text Recognition v2で日本語認識Androidアプリ - Qiita
12/18 [Ansible] Assume Roleモジュールを使う - mito’s blog
12/19 [Terraform] 関数を使って、年月日時分秒をユニークな文字列として扱う - mito’s blog
12/20 フロントエンドを知らない一般人がトレンディなフレームワーク SvelteKit を眺める - ローカル環境構築編 -
12/21 GAEの起動/停止をスケジューリングする
12/22 フロントエンドを知らない一般人がトレンディなフレームワーク SvelteKit を眺める - ルーティング編 -
12/23 非技術者がJavaScriptフレームワーク・ライブラリの違いを調べてみた - Qiita
12/24 【対策メモ】AWS認定DevOpsエンジニア-プロフェッショナル試験 - Qiita
12/25 【合格体験記】AWS認定DevOpsエンジニア-プロフェッショナル(DOP-C01) - Qiita


最後に

来年も開催したいなと思います。 順調に埋まるように(それだけじゃないけど)、じわじわと他部署にもアウトプットの芽を埋めてみます。

[Terraform] 関数を使って、年月日時分秒をユニークな文字列として扱う

この記事は、カサレアル Advent Calendar 2022 の19日目のエントリです。

はじめに

ユニークな文字列が欲しかったので、年月日時分秒を取得し文字列にしました。
以下の関数を組み合わせます。


TFファイル

現在の時間2022年12月18日11時26分29秒20221218112629に変換します。

  • tfファイル
locals {
  # timestampでUTCを取得する
  now_utc = timestamp()
  # timeaddで9hを足してJSTに変換する
  now_jst = timeadd(local.now_utc, "9h") 
  # formatdateで取得したい形式に変換する
  datetime = formatdate("YYYYMMDDhhmmss", local.now_jst)
}

output "datetime"{
  value = local.datetime
}


実行結果

$ terraform apply

Changes to Outputs:
  + datetime = (known after apply)

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes


Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

datetime = "20221218112629"
$ 


備考

24時間表記にするため、formatdate関数ではhhを指定します。


[Ansible] Assume Roleモジュールを使う

この記事は、カサレアル Advent Calendar 2022 の18日目のエントリです。

はじめに

最近、AnsibleのAWSコレクションにamazon.awsとcommunity.awsの2つがあることを知りました。
community.awsのほうにAssume Roleモジュールがあったので、それを試してみます。

なお、AssumeRoleってなに?という方は、記憶に残しやすい記事がありますのでご参照ください。


環境

  • ansible core: 2.13.7
  • community.aws: 5.0.0

community.awsの最新版は、Ansible Core 2.11.0以前のバージョンをサポートしていません。

Ansible version compatibility Tested with the Ansible Core 2.12, and 2.13 releases, and the current development version of Ansible. Ansible Core versions before 2.11.0 are not supported. In particular, Ansible Core 2.10 and Ansible 2.9 are not supported.


AssumeRole する Playbook

sts_assume_roleモジュールの実行前後で、ARNやクレデンシャル情報等を出力します。

---
- hosts: localhost
  gather_facts: no

  tasks:
    - shell:
        cmd: aws sts get-caller-identity
      register: result

    - name: before
      debug:
        msg: "{{ result.stdout }}"

    - name: set assume_role
      sts_assume_role:
        role_arn: "arn:aws:iam::*******:role/********"  #引き継ぎたいRoleを指定
        role_session_name: "Test_Role"
      register:  assumed_role

    - name: after
      debug:
        msg: "{{ assumed_role }}"


Playbook の実行結果

sts_assume_roleモジュールにより、ARNや一時的なクレデンシャル情報等が設定されました(ほぼ伏字ですが)。

$ ansible-playbook assume_role.yml 
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ********************************************************************

TASK [shell] ************************************************************************
changed: [localhost]

TASK [before] ***********************************************************************
ok: [localhost] => {
    "msg": {
        "Account": "***********",
        "Arn": "arn:aws:iam::***********:user/***********",
        "UserId": "***********"
    }
}

TASK [set assume_role] **************************************************************
changed: [localhost]

TASK [after] ************************************************************************
ok: [localhost] => {
    "msg": {
        "changed": true,
        "failed": false,
        "sts_creds": {
            "access_key": "***********",
            "expiration": "2022-12-17T17:31:46+00:00",
            "secret_key": "**********************",
            "session_token": "*********************************"
        },
        "sts_user": {
            "arn": "arn:aws:sts::***********:assumed-role/***********/Test_Role",
            "assumed_role_id": "***********:Test_Role"
        }
    }
}

PLAY RECAP **************************************************************************
localhost : ok=4  changed=2  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0   

$ 


以降のタスクでaws_access_key: "{{ assumed_role.sts_creds.access_key }}"のように指定し、AssumeRole後のクレデンシャル情報等を使用します。

[Ansible] ダイナミックインベントリで起動中のインスタンスのIPアドレスを出力する

この記事は、Ansible Advent Calendar 2022 の9日目のエントリです。

はじめに

ダイナミックインベントリを使う時はデフォルトのDNS名をhostsに指定していたのですが、ほかの指定はできないのかと思い、IPアドレスを対象に実施してみました。


インベントリファイル

ファイル名は、仕様でaws_ec2.ymlか***aws_ec2.ymlとする必要があります。

$ cat aws_ec2.yml
---
plugin: amazon.aws.aws_ec2
regions:
  - ap-northeast-1
hostnames:
  # 結果をプライベートIPで出力する。パブリックIPは「ip-address」を指定する
  - private-ip-address
include_filters:
  # リストの中に複数の条件をいれると、andでつながる
  - instance-state-name: running
    tag:Name:
    # ワイルドカードが使える
    - "web_*"
compose:
  ansible_host: private_ip_address     # hostsにプライベートIPをしているので、今回は不要

$ 


実行ログ

インスタンスの状況は以下です。

Name インスタンスの状態 プライベートIPアドレス
web_01 実行中 172.31.36.***
web_02 実行中 172.31.32.***
web_03 停止済み 172.31.41.***
weeeeebb!!! 実行中 172.31.16.***


ansible-inventoryコマンドを実行し、確認します。

$ ansible-inventory -i aws_ec2.yml --graph
@all:
  |--@aws_ec2:
  |  |--172.31.32.***
  |  |--172.31.36.***
  |--@ungrouped:
$ 


起動中のweb_01、web_02のプライベートIPアドレスのみ出力できました。


注意

プライベートIPアドレスインスタンスが停止していても割り当てられているので、aws_ec2.ymlのフィルターにあるinstance-state-name : runningが必要です。

aws_ec2.ymlからinstance-state-name : runningを削除した場合、以下のように停止中のインスタンスも表示されます。

$ cat aws_ec2.yml 
---
plugin: amazon.aws.aws_ec2
regions:
  - ap-northeast-1
hostnames:
  - private-ip-address
include_filters:
  - tag:Name:
    - "web_*"
$ 
$ ansible-inventory -i aws_ec2.yml --graph
@all:
  |--@aws_ec2:
  |  |--172.31.32.***
  |  |--172.31.36.***
  |  |--172.31.41.***
  |--@ungrouped:
$ 


参考

フィルターの条件をandにする方法が分からなかったので助かりました!

フィルターなどの条件に指定できるEC2インスタンスのパラメータは以下のようです。

[Ansible x Terraform] local-execでPlaybookを実行してみた


この記事は、Ansible Advent Calendar 2022 の2日目のエントリです。

はじめに

今回はAnsibleのTerraformモジュールを使うのではなく、TerraformでEC2インスタンスを作成し、local-execでPlaybookを実行してパッケージをインストールします。
AnsibleのAmazonEC2のインベントリプラグインは使わず、出来る限りTerraformで実装してみます。

Provisioner: local-exec | Terraform | HashiCorp Developer



結論

Playbookを更新しても一度それを実行するnull_resourceが成功していれば、terraform applyでは差異なしと判断され、null_resource(Playbook)は再実行されません。
また、Terrafromが出力するPlaybookのログがきれいに表示されないので、AnsibleからTerraformを呼び出したほうが便利そうです。


環境

  • terraform: v1.3.4
  • ansible core: v2.13.6
  • aws cli: v1.22.34


用意するファイル

  • main.tf
    • 実装内容
      • EC2インスタンスの作成
      • SSHキーの作成
      • セキュリティグループの作成
      • リソースhttpでホストのパブリックIPを取得する
      • リソースlocal_fileでinventory.iniの作成
      • リソースnull_resourceのlocal-execでPlaybookを実行する
  • main.yml
    • 実装内容
      • gitのインストール
  • ansible.cfg
    • 実装内容
      • host_key_checkingの無効


main.tf
provider "aws" {
    region = "ap-northeast-1"
    access_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    secret_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

# EC2インスタンスの作成
resource "aws_instance" "mito_ec2" {
    ami           = "ami-072bfb8ae2c884cc4"    # Amazon Linux 2
    instance_type = "t2.micro"
    associate_public_ip_address = "true"
    key_name      = aws_key_pair.deployer.key_name
    vpc_security_group_ids = [aws_security_group.sg_mito.id]
    tags = {
        Name = "mito_ec2"
    }
}

# キーペアの作成
resource "tls_private_key" "rsa_4096" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

resource "aws_key_pair" "deployer" {
  key_name   = "mito_key"
  public_key = tls_private_key.rsa_4096.public_key_openssh
  lifecycle {
    ignore_changes  = [key_name]
  }
}

resource "local_file" "private_key_pem" {
  content  = tls_private_key.rsa_4096.private_key_pem
  filename = "/home/ubuntu/.ssh/mito_key.pem"  # ログインユーザに合わせる
}

# セキュリティグループの作成
resource "aws_security_group" "sg_mito" {
  name        = "sg_mito"
  description = "sg_mito"

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["${chomp(data.http.myip.response_body)}/32"]  # ホストのパブリックIPを許可する
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name      = "sg_mito"
  }
}

# 返り値でホストのパブリックIPを取得する
data "http" "myip" {
  url = "http://ipv4.icanhazip.com"
}

# 対象ノードのプライベートIPが記載されたinventory.iniを作成する
resource "local_file" "inventory" {
  content  = aws_instance.mito_ec2.public_ip
  filename = "./inventory.ini"
  file_permission = "0644"
}

# Playbookの実行
resource "null_resource" "playbook" {
  depends_on = [
    aws_instance.mito_ec2  # インスタンス作成後に実行
  ]

  # 対象ノードの起動を待ち、Playbookを実行する
  provisioner "local-exec" {
    interpreter = ["/usr/bin/bash", "-c"]
    command     = <<-EOT
      chmod 600 ${local_file.private_key_pem.filename}
      aws ec2 wait instance-status-ok --instance-ids ${aws_instance.mito_ec2.id}
      ansible-playbook main.yml -i inventory.ini -u ec2-user --private-key=${local_file.private_key_pem.filename}
    EOT
  }
}


main.yml
---
- hosts: all
  gather_facts: no
  become: yes

  tasks:
    - name: install git
      yum:
        name: git
        state: present


ansible.cfg
[defaults]
host_key_checking = False


実行ログ

99行目からPlaybookのログが表示されていますが、ログの順番が変わっています。

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/null from the dependency lock file
- Reusing previous version of hashicorp/tls from the dependency lock file
- Finding latest version of hashicorp/http...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Reusing previous version of hashicorp/local from the dependency lock file
- Using previously-installed hashicorp/null v3.2.1
- Using previously-installed hashicorp/tls v4.0.4
- Installing hashicorp/http v3.2.1...
- Installed hashicorp/http v3.2.1 (signed by HashiCorp)
- Using previously-installed hashicorp/aws v4.43.0
- Using previously-installed hashicorp/local v2.2.3

()
$ 
$ 
$ terraform apply
data.http.myip: Reading...
data.http.myip: Read complete after 0s [id=http://ipv4.icanhazip.com]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.mito_ec2 will be created
  + resource "aws_instance" "mito_ec2" {
      + ami                                  = "ami-072bfb8ae2c884cc4"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = true
      + availability_zone                    = (known after apply)
() 

  # local_file.inventory will be created
  + resource "local_file" "inventory" {
      + content              = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0644"
      + filename             = "./inventory.ini"
      + id                   = (known after apply)
    }

  # local_file.private_key_pem will be created
  + resource "local_file" "private_key_pem" {
      + content              = (sensitive)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "/home/ubuntu/.ssh/mito_key.pem"
      + id                   = (known after apply)
    }

  # null_resource.playbook will be created
  + resource "null_resource" "playbook" {
      + id = (known after apply)
    }

()
Plan: 7 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

tls_private_key.rsa_4096: Creating...
aws_security_group.sg_mito: Creating...
tls_private_key.rsa_4096: Creation complete after 1s [id=6d5549db0XXXXXXXXXXXXXXXXX]
local_file.private_key_pem: Creating...
aws_key_pair.deployer: Creating...
local_file.private_key_pem: Creation complete after 0s [id=9f5e11483XXXXXXXXXXXXXXXXXXXX]
aws_key_pair.deployer: Creation complete after 0s [id=mito_key]
aws_security_group.sg_mito: Creation complete after 3s [id=sg-091fbXXXXXXXXXXXX]
aws_instance.mito_ec2: Creating...
aws_instance.mito_ec2: Still creating... [10s elapsed]
aws_instance.mito_ec2: Still creating... [20s elapsed]
aws_instance.mito_ec2: Creation complete after 21s [id=i-02fb1XXXXXXXXXXXX]
local_file.inventory: Creating...
null_resource.playbook: Creating...
local_file.inventory: Creation complete after 0s [id=fecdbeXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
null_resource.playbook: Provisioning with 'local-exec'...
null_resource.playbook (local-exec): Executing: ["/usr/bin/bash" "-c" "chmod 600 /home/ubuntu/.ssh/mito_key.pem\naws ec2 wait instance-status-ok --instance-ids i-02fb1149af69d72ce\nansible-playbook main.yml -i inventory.ini -u ec2-user --private-key=/home/ubuntu/.ssh/mito_key.pem\n"]
null_resource.playbook: Still creating... [10s elapsed]
null_resource.playbook: Still creating... [20s elapsed]
null_resource.playbook: Still creating... [30s elapsed]
null_resource.playbook: Still creating... [40s elapsed]
null_resource.playbook: Still creating... [50s elapsed]
null_resource.playbook: Still creating... [1m0s elapsed]
null_resource.playbook: Still creating... [1m10s elapsed]
null_resource.playbook: Still creating... [1m20s elapsed]
null_resource.playbook: Still creating... [1m30s elapsed]
null_resource.playbook: Still creating... [1m40s elapsed]

null_resource.playbook (local-exec): PLAY [all] *********************************************************************

null_resource.playbook (local-exec): TASK [install git] *************************************************************
null_resource.playbook: Still creating... [1m50s elapsed]
null_resource.playbook (local-exec): [WARNING]: Platform linux on host xx.xx.xx.xx is using the discovered Python
null_resource.playbook (local-exec): interpreter at /usr/bin/python3.7, but future installation of another Python
null_resource.playbook (local-exec): interpreter could change the meaning of that path. See
null_resource.playbook (local-exec): https://docs.ansible.com/ansible-
null_resource.playbook (local-exec): core/2.13/reference_appendices/interpreter_discovery.html for more information.
null_resource.playbook (local-exec): changed: [xx.xx.xx.xx]

null_resource.playbook (local-exec): PLAY RECAP *********************************************************************
null_resource.playbook (local-exec): xx.xx.xx.xx  : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

null_resource.playbook: Creation complete after 1m54s [id=6559XXXXXXXXXXXXXX]

Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
$ 

[Ansible x Terraform] TerraformでKeyPairの作成やAmazon Secrets ManagerにKeyPairを登録し、Ansibleで利用する

この記事は、カサレアル Advent Calendar 2022 の2日目のエントリです。

はじめに

TerraformでEC2インスタンスやKerPairなどのリソースを作成し、それをAnsibleで活用します。
以下の流れで試します。

  1. [Terraform] EC2インスタンスSSHキー(KeyPair)などのリソースを作成します
  2. [Terraform] Amazon Secrets ManagerにSSHキーを登録します
  3. [Ansible] Amazon Secrets ManagerからSSHキーをダウンロードします
  4. [Ansible] SSHキーを使って、対象ノードにパッケージをインストールします



Terraformのリソース「Secrets Manager」について

リソースaws_secretsmanager_secretでシークレットの名前を、リソースaws_secretsmanager_secret_versionでユーザ名/パスワードやキー/バリューなどのシークレット情報が登録できます。

Terraform Registry

locals {
  KEY = {
    ssh_key = file("./xxxx.pem")
  }
}

resource "aws_secretsmanager_secret" "asm_secret" {
  name = "シークレット名"
}

resource "aws_secretsmanager_secret_version" "asm_secret_version" {
  secret_id     = aws_secretsmanager_secret.asm_secret.id
  secret_string = jsonencode(local.KEY)
}


Ansibleのlookupプラグインamazon.aws.aws_secret」について

lookupプラグインを使って、Amazon Secrets ManagerからKerPair情報を取得します。

amazon.aws.aws_secret lookup – Look up secrets stored in AWS Secrets Manager — Ansible Documentation

"{{ lookup('amazon.aws.aws_secret', 'シークレット名', region='リージョン', aws_access_key='XXXXXX', aws_secret_key='XXXXXX') }}"


環境

  • ホストOS: Amazon Linux 2
  • 対象ノードOS: Amazon Linux 2(terraformで作成)
  • terraform: v1.3.4
  • ansible core: v2.13.6
  • amazon.aws: v5.1.0
  • Python: v3.10.6
  • python3-boto: v2.49.0-4
  • python3-botocore: v1.23.34


用意するファイル

  • main.tf
    • 実装内容
      • EC2インスタンスを作成する
      • KeyPairを作成する
      • Secrets ManagerへKeyPairを登録する
      • セキュリティグループを作成する
        • ホストからのSSHアクセスを許可する
  • main.yml
    • 実装内容
      • Secrets ManagerからKeyPairを取得する
      • KeyPairを使ってgitをインストールする
  • ansible.cfg
    • 実装内容
      • host_key_checkingの無効


main.tf
provider "aws" {
    region = "ap-northeast-1"
    access_key = "XXXXXX"
    secret_key = "XXXXXX"
}

# EC2インスタンスの作成
resource "aws_instance" "mito_ec2" {
    ami           = "ami-072bfb8ae2c884cc4"    # Amazon Linux 2
    instance_type = "t2.micro"
    associate_public_ip_address = "true"
    key_name      = aws_key_pair.deployer.key_name
    vpc_security_group_ids = [aws_security_group.sg_mito.id]
    tags = {
        Name = "mito_ec2"
    }
}

# キーペアの作成
resource "tls_private_key" "rsa_4096" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

resource "aws_key_pair" "deployer" {
  key_name   = "mito_key"
  public_key = tls_private_key.rsa_4096.public_key_openssh
  lifecycle {
    ignore_changes  = [key_name]
  }
}

# セキュリティグループの作成
resource "aws_security_group" "sg_mito" {
  name        = "sg_mito"
  description = "sg_mito"

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["${chomp(data.http.myip.response_body)}/32"]  # ホストのパブリックIPを許可する
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name      = "sg_mito"
  }
}

# 返り値でホストのパブリックIPを取得する
data "http" "myip" {
  url = "http://ipv4.icanhazip.com"
}

# Secrets ManagerSSHキーを登録する
resource "aws_secretsmanager_secret" "asm_secret" {
  name = "test_asm_secret"
}

resource "aws_secretsmanager_secret_version" "asm_secret_version" {
  secret_id     = aws_secretsmanager_secret.asm_secret.id
  secret_string = jsonencode( {"ssh_key" = tls_private_key.rsa_4096.private_key_pem})
}


main.yml

1Play目でSSHキーをダウンロードし、2Play目でパッケージをインストールします。

---
- hosts: localhost
  gather_facts: no

  tasks:
    - name: create ssh_key
      ansible.builtin.copy:
        content: "{{ key.ssh_key}}"
        dest: ./mito_key.pem
        mode: 0600
      vars:
        key: "{{ lookup('amazon.aws.aws_secret', 'test_asm_secret', region='ap-northeast-1', aws_access_key='XXXXXX', aws_secret_key='XXXXXX') }}"

- hosts: all
  gather_facts: no
  become: yes

  tasks:
    - name: install git
      yum:
        name: git
        state: present


ansible.cfg
[defaults]
host_key_checking = False


実行ログ

まずは、Terraformコマンドでリソースを作成します。

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/tls...
- Finding latest version of hashicorp/http...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/tls v4.0.4...
- Installed hashicorp/tls v4.0.4 (signed by HashiCorp)
- Installing hashicorp/http v3.2.1...
- Installed hashicorp/http v3.2.1 (signed by HashiCorp)
- Installing hashicorp/aws v4.44.0...
- Installed hashicorp/aws v4.44.0 (signed by HashiCorp)
()
$ 
$ 
$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.mito_ec2 will be created
  + resource "aws_instance" "mito_ec2" {
      + ami                                  = "ami-072bfb8ae2c884cc4"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = true
      + availability_zone                    = (known after apply)

()
  # aws_secretsmanager_secret.asm_secret will be created
  + resource "aws_secretsmanager_secret" "asm_secret" {
      + arn                            = (known after apply)
      + force_overwrite_replica_secret = false
      + id                             = (known after apply)
      + name                           = "test_asm_secret"
      + name_prefix                    = (known after apply)
      + policy                         = (known after apply)
      + recovery_window_in_days        = 30
      + rotation_enabled               = (known after apply)
      + rotation_lambda_arn            = (known after apply)
      + tags_all                       = (known after apply)

      + replica {
          + kms_key_id         = (known after apply)
          + last_accessed_date = (known after apply)
          + region             = (known after apply)
          + status             = (known after apply)
          + status_message     = (known after apply)
        }

      + rotation_rules {
          + automatically_after_days = (known after apply)
        }
    }

  # aws_secretsmanager_secret_version.asm_secret_version will be created
  + resource "aws_secretsmanager_secret_version" "asm_secret_version" {
      + arn            = (known after apply)
      + id             = (known after apply)
      + secret_id      = (known after apply)
      + secret_string  = (sensitive value)
      + version_id     = (known after apply)
      + version_stages = (known after apply)
    }

()
Plan: 6 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

tls_private_key.rsa_4096: Creating...
aws_secretsmanager_secret.asm_secret: Creating...
aws_security_group.sg_mito: Creating...
()

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
$ 


AWSコンソールでシークレットマネージャへのSSHキー登録を確認します。


作成したEC2インスタンスのinventory.iniを作成します。

$ cat inventory.ini 
35.79.224.19


Playbookを実行します。

 $ ansible-playbook main.yml -i inventory.ini -u ec2-user --private-key=./mito_key.pem
[DEPRECATION WARNING]: Ansible will require Python 3.8 or newer on the controller starting with Ansible 2.12. Current version: 3.7.10 (default, Jun  3 2021, 00:02:01) [GCC 7.3.1 20180712 (Red Hat 7.3.1-13)]. This feature will be removed from 
ansible-core in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

PLAY [localhost] ********************************************************************************

TASK [create ssh_key] ***************************************************************************
changed: [localhost]

PLAY [all] **************************************************************************************

TASK [install git] ******************************************************************************
[WARNING]: Platform linux on host 35.79.224.19 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-
core/2.11/reference_appendices/interpreter_discovery.html for more information.
changed: [35.79.224.19]

PLAY RECAP **************************************************************************************
35.79.224.19   : ok=1  changed=1  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0   
localhost      : ok=1  changed=1  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0   

$ 


無事に対象ノードへ接続し、パッケージもインストールできました。

備考

inventory.iniの作成はダイナミックインベントリを使えば不要になるけど手、 SSHキー名などの固定値は、別途管理する必要があります。

[AWS Backup] バックアップとリストアを試してみた

この記事は、カサレアル Advent Calender 2022 の1日目のエントリです。

はじめに

AWS Backup を知ったので、EC2インスタンスを対象にバックアップとリストアを試してみました。

AWS Backup とは?

AWS Backup はフルマネージド型のバックアップサービスであり、AWS のサービス、クラウド内、およびオンプレミス間で簡単に一元化およびデータ保護を自動化できます。

このサービスを使用すると、1 つの場所でバックアップポリシーを設定し、AWS リソースのアクティビティを監視できます。

AWS Backup とは? - AWS Backup




検証用のEC2インスタンスを用意する

検証で使っていたAnsibleサーバがあったので、それを対象とします。
また、リストア後の比較用にインスタンス情報を取得します。

$ aws ec2 describe-instances --instance-ids i-0cf8XXXXXXXXXXXX >> source.txt
$ cat source.txt 
{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "ami-03f4XXXXXXXXXXXX",
                    "InstanceId": "i-0cf8XXXXXXXXXXXX",
                    "InstanceType": "t3.medium",
                    "KeyName": "xxxxx",
                    "LaunchTime": "2022-11-30T00:19:37.000Z",
                    "Monitoring": {
                        "State": "disabled"
                    },
略


Ansibleのバージョンを確認します。

$ ansible --version
ansible [core 2.13.6]


EC2インスタンスのバックアップを取得する

コンソールを操作し、バックアップを取得します。
インスタンスIDはAnsibleサーバを指定します。

10分程度で完了しました。


バックアップ情報からリストアする

コンソールを操作し、リストアします。


バックアップを取得したEC2インスタンスはそのままで、新たにEC2インスタンスが作成されます
また、Tag.Nameは空白です。

$ aws ec2 describe-instances --instance-id i-07b2XXXXXXXXXXXX >> restore.txt
$ cat restore.txt 
{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "ami-0604XXXXXXXXXXXX",
                    "InstanceId": "i-07b2XXXXXXXXXXXX",
                    "InstanceType": "t3.medium",
                    "KeyName": "xxxxx",
                    "LaunchTime": "2022-11-30T05:45:16.000Z",
                    "Monitoring": {
                        "State": "disabled"
                    },
略


5分程度で完了しました。
Ansibleのバージョンは変わらずで、無事リストアできました。

$ ansible --version
ansible [core 2.13.6]


バックアップ元のインスタンスとリストアしたインスタンスを比較する

取得したインスタンス情報を比較した結果です。

差分あり

  • ImageId
  • InstanceId
  • PrivateDnsName
  • PrivateIpAddress
  • PublicDnsName
  • PublicIpAddress
  • VolumeId
  • ClientToken
  • IamInstanceProfile
    • IAMロール無しでリストアしたため、リストアしたインスタンスは無し
  • MacAddress
  • NetworkInterfaceId
  • Tags.Name
  • EnableResourceNameDnsARecord
  • ReservationId
  • RequesterId
  • timestampをパラメータに持つKey
// timestampが差分のキーは除外しています
ubuntu@ip-172-31-31-169:~$ diff source.txt restore.txt
8,9c8,9
<                     "ImageId": "ami-03f4XXXXXXXXXXXX",
<                     "InstanceId": "i-0cf8XXXXXXXXXXXX",
---
>                     "ImageId": "ami-0604XXXXXXXXXXXX",
>                     "InstanceId": "i-07b2XXXXXXXXXXXX",
21,22c21,22
<                     "PrivateDnsName": "ip-172-31-XX-XXX.ap-northeast-1.compute.internal",
<                     "PrivateIpAddress": "172.31.XX.XXX",
---
>                     "PrivateDnsName": "ip-172-31-XXX-XXX.ap-northeast-1.compute.internal",
>                     "PrivateIpAddress": "172.31.XXX.XXX",
24,25c24,25
<                     "PublicDnsName": "ec2-18-178-XXX-XXX.ap-northeast-1.compute.amazonaws.com",
<                     "PublicIpAddress": "18.178.XXX.XXX",
---
>                     "PublicDnsName": "ec2-43-206-XXX-XXX.ap-northeast-1.compute.amazonaws.com",
>                     "PublicIpAddress": "43.206.XXX.XXX",
41c41
<                                 "VolumeId": "vol-0906XXXXXXXXXXX"
---
>                                 "VolumeId": "vol-0e2cXXXXXXXXXXX"
45c45
<                     "ClientToken": "165XXXXX-XXXX-XXXX",
---
>                     "ClientToken": "E65XXXXX-XXXX-XXXX",
49,52d48
<                     "IamInstanceProfile": {
<                         "Arn": "arn:aws:iam::XXXXXXXXX:instance-profile/AmazonSSMRoleForInstancesQuickSetup",
<                         "Id": "AIXXXXXXXXXXXXX"
<                     },
76,77c72,73
<                             "MacAddress": "0e:de:XX:XX:XX:XX",
<                             "NetworkInterfaceId": "eni-07aXXXXXXXXXX",
---
>                             "MacAddress": "0e:3a:XX:XX:XX:XX",
>                             "NetworkInterfaceId": "eni-047XXXXXXXXXX",
109,114d104
<                     "Tags": [
<                         {
<                             "Key": "Name",
<                             "Value": "XXXXXX"
<                         }
<                     ],
142c132
<                         "EnableResourceNameDnsARecord": true,
---
>                         "EnableResourceNameDnsARecord": false,
148c138,139
<             "ReservationId": "r-0acXXXXXXXXXX"
---
>             "RequesterId": "16XXXXXXXXXX",
>             "ReservationId": "r-0310XXXXXXXXXX"
$ 


備考

リストアする際、インスタンスプロファイルのIAMロールにBackupがないと、以下のエラーが表示されます。
IAMロールに「iam:PassRole アクセス許可」を追加するか、IAMロールなしでリストアし、リストア後にIAMロールを付与することで解決します。

AWS Backup を使用して Amazon EC2 インスタンスを復元するときに表示されるエンコードされた認可エラーメッセージのトラブルシューティング