mito’s blog

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

[terraform] S3とTransferFamilyでsftpサーバを作る

この記事は、terraform Advent Calendar 2024 の7日目のエントリです。

はじめに

terraformで、AWS S3とTransferFamilyを組み合わせて、さっとsftpサーバを作ります。
sftpユーザや鍵ファイルも併せて作るので、apply後にsftp接続できます。 なお、tfstateに公開鍵も秘密鍵も記載されているため気を付けてください。
(Transfer Familyを触ったのは初めてでした。知らないサービス多すぎ!)

AWS Transfer Familyとは
完全マネージドなファイル転送サービスで、SFTP、FTPS、FTPを使用して、安全にデータをAWSに移動できます。
各接続方式や接続先サービス(s3、EFS)を選択したサーバを用意し、それに対して、アクセスするユーザやロール、接続先(S3バケット名など)を指定します。 Transferのサーバーはあくまで接続に関する情報のまとまりであり、例えばS3バケット名を紐づけるわけではないです。そのため、1つのサーバーに対し、異なるロールや異なるアクセス先をもつユーザを設定できます。

参考 Terraform Registry




環境

環境と設定

  • terraform : v1.9.4
  • バケット名 : advent-server
  • sftpユーザ名 : sftp-advent


ファイル構成

$ tree ./
./
├── main.tf
├── output.tf
├── terraform.tfvars
└── variables.tf


各ファイルについて

terraform.tfvars

バケット名、sftpユーザ名、アクセス記録のためのロググループの変数を用意します。

bucket_name = "advent-server"
sftp_user = "sftp-advent"
log_group = "/transfer/advent-server"


variables.tf

各変数を定義します。

variable "bucket_name" {
  type = string
}

variable "sftp_user" {
  type = string
}

variable "log_group" {
  type = string
}


main.tf

作成するリソースとポイントを記載します。

  • s3バケット
    • force_destroy = true
  • transferに設定するロールとポリシー
    • ロールにポリシーをアタッチします
  • transferに設定するロググループ
  • transferサーバー
    • sftp接続で作成します
  • sftpユーザと鍵ファイル
provider "aws" {
  region     = "ap-northeast-1"
  access_key = "AKIA**********"
  secret_key = "**************"
}

resource "aws_s3_bucket" "bucket" {
  bucket        = var.bucket_name
  force_destroy = true                 # バケット削除時にオブジェクトも削除する
}

resource "aws_iam_role" "transfer_role" {
  name = "TransferFamilyS3AccessRole"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        "Sid" : "",
        "Effect" : "Allow",
        "Principal" : {
          "Service" : "transfer.amazonaws.com"
        },
        "Action" : "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_policy" "s3_access_policy" {
  name = "S3AccessPolicyForTransferFamily"
  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        "Sid" : "Statement1",
        "Effect" : "Allow",
        "Action" : [
          "s3:ListBucket",
          "s3:GetBucketLocation"
        ],
        "Resource" : "${aws_s3_bucket.bucket.arn}"
      },
      {
        "Sid" : "Statement2",
        "Effect" : "Allow",
        "Action" : [
          "s3:PutObject",
          "s3:GetObject",
          "s3:DeleteObject"
        ],
        "Resource" : "${aws_s3_bucket.bucket.arn}/*"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "attach_s3_policy" {
  role       = aws_iam_role.transfer_role.name
  policy_arn = aws_iam_policy.s3_access_policy.arn
}

resource "aws_cloudwatch_log_group" "transfer" {
  name_prefix = var.log_group
}

resource "aws_transfer_server" "sftp_server" {
  domain                 = "S3"
  protocols              = ["SFTP"]             # SFTPは鍵認証のみ使えます
  identity_provider_type = "SERVICE_MANAGED"
  endpoint_type          = "PUBLIC"             # 外部から接続できるようにする

  structured_log_destinations = [
    "${aws_cloudwatch_log_group.transfer.arn}:*"
  ]

  tags = {
    Name = "transfer-${var.bucket_name}"
  }

}

resource "aws_transfer_user" "sftp_user" {
  server_id      = aws_transfer_server.sftp_server.id
  user_name      = var.sftp_user
  role           = aws_iam_role.transfer_role.arn
  home_directory = "/${var.bucket_name}"
}

resource "tls_private_key" "sftp_tls" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

resource "aws_transfer_ssh_key" "sftp_ssh_key" {      # SFTP接続は鍵認証のみ。
  server_id = aws_transfer_server.sftp_server.id
  user_name = aws_transfer_user.sftp_user.user_name
  body      = trimspace(tls_private_key.sftp_tls.public_key_openssh)
}

resource "local_file" "private_key_file" {
  content         = tls_private_key.sftp_tls.private_key_pem
  file_permission = "0600"
  filename        = pathexpand("~/.ssh/${var.sftp_user}.pem")
}


output.tf

接続するためのsftpエンドポイントを表示します。

output "sftp_endpoint" {
  value = aws_transfer_server.sftp_server.endpoint
}


terraformの実行

terraform apply

transferの作成に3分ほどかかりました。

$ 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_cloudwatch_log_group.transfer will be created
  + resource "aws_cloudwatch_log_group" "transfer" {
(略)

Plan: 10 to add, 0 to change, 0 to destroy.

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

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.sftp_tls: Creating...
aws_cloudwatch_log_group.transfer: Creating...
aws_iam_role.transfer_role: Creating...
aws_s3_bucket.bucket: Creating...
(略)
Apply complete! Resources: 10 added, 0 changed, 0 destroyed.

Outputs:

sftp_endpoint = "******.server.transfer.ap-northeast-1.amazonaws.com"
$ 


sftp接続

sftp接続し、ファイルのアップロードやダウンロードが確認できました。

$ sftp -i ~/.ssh/sftp-advent.pem sftp-advent@******.server.transfer.ap-northeast-1.amazonaws.com
Connected to ******.server.transfer.ap-northeast-1.amazonaws.com.
sftp> pwd
Remote working directory: /advent-server
sftp> ls
sftp> put main.tf 
Uploading main.tf to /advent-server/main.tf
maintf                 100% 2565    59.0KB/s   00:00    
sftp> ls
main.tf  
sftp> get main.tf 
Fetching /advent-server/main.tf to main.tf
main.tf       
sftp> exit
$ 


その他

terraform destroyで、バケットにファイルが残っていても全て削除できます。ローカルの秘密鍵も削除されます。

また、カスタムホスト名を付与するならRoute53でホストゾーンとレコードを作成します。
マネジメントコンソールでカスタムホスト名を付けてPlanしたところ、タグのみの差異だったため、ちょっとめんどくさがってコードにそのタグを付けたらホストゾーンとレコードも作成されました。この場合、destroyしてもホストゾーンは残っていたので、このやり方はあまりよくないんだろうなと思いました。

[Ansible] AWS TransferFamily / S3用のロールとポリシーを作成する

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

はじめに

Ansibleで、AWS TransferFamily経由でS3にアクセスするためのロールとそれにアタッチするポリシーを作ります。 Transfer Familyの作成もコード化したかったのですが、現時点ではモジュールがありませんでした。

なお、削除するには削除用のPlaybookを用意することになります。例えば、state:absentに変えただけでは削除順番でエラーになるため入れ替えたり、インスタンスプロファイルが残るので削除するためのモジュールを追加することになるかと思います。
まぁそれもこれもやってみないとわからなかったし、TransferFamily 以外にも流用できるのでヨシ!!




環境とパラメータ

  • ansible : core 2.18.0
  • バケット名 : advent-server
  • ロール名 : TransferFamilyS3AccessRole
  • ポリシー名 : TransferFamilyS3AccessPolicy


Playbook

ポリシーはPlaybookに直接記載しています。

---
- name: Set up role for Transfer Family
  hosts: localhost
  gather_facts: no
  vars:
    bucket_name: advent-server
    role_name: TransferFamilyS3AccessRole
    policy_name: TransferFamilyS3AccessPolicy

  tasks:
#    - name: Create S3 bucket # パブリックアクセスはデフォルトですべてブロック
#      amazon.aws.s3_bucket:
#        name: "{{ bucket_name }}"
#        state: present

    - name: Create a role # Transfer Familyにアクセスする
      amazon.aws.iam_role:
        name: "{{ role_name }}"
        assume_role_policy_document: |
          {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Sid": "",
                "Effect": "Allow",
                "Principal": {
                  "Service": "transfer.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
              }
            ]
          }
        state: present
        
    - name: Create a policy for s3 access # S3アクセスポリシーを作成し、ロールに付与する
      amazon.aws.iam_policy:
        iam_name: "{{ role_name }}"
        iam_type: "role"
        policy_name: "{{ policy_name }}"
        policy_json: |
          {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Sid": "Statement1",
                "Effect": "Allow",
                "Action": [
                  "s3:ListBucket",
                  "s3:GetBucketLocation"
                ],
                "Resource": [
                  "arn:aws:s3:::{{ bucket_name }}"
                ]
              },
              {
                "Sid": "Statement2",
                "Effect": "Allow",
                "Action": [
                  "s3:PutObject",
                  "s3:GetObject",
                  "s3:DeleteObject"
                ],
                "Resource": "arn:aws:s3:::{{ bucket_name }}/*"
              }
            ]
          }
        state: present
      register: iam_policy
      
    - ansible.builtin.debug:
        msg: "{{ iam_policy }}"


実行ログ

いくつかワーニングが出ていますが、動作に影響はないです。

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

PLAY [Set up role for Transfer Family] *******************************************************************

TASK [Create a role] *************************************************************************************
[DEPRECATION WARNING]: In a release after 2026-05-01 iam_role.assume_role_policy_document_raw will no longer be returned.  Since release 8.0.0 assume_role_policy_document has been 
returned with the same format as iam_role.assume_role_policy_document_raw. This feature will be removed from amazon.aws in a release after 2026-05-01. Deprecation warnings can be 
disabled by setting deprecation_warnings=False in ansible.cfg.
[DEPRECATION WARNING]: In a release after 2026-05-01 the 'create_instance_profile' option will be removed. The amazon.aws.iam_instance_profile module can be used to manage instance 
profiles instead. This feature will be removed from amazon.aws in a release after 2026-05-01. Deprecation warnings can be disabled by setting deprecation_warnings=False in 
ansible.cfg.
[DEPRECATION WARNING]: In a release after 2026-05-01 the 'delete_instance_profile' option will be removed. The amazon.aws.iam_instance_profile module can be used to manage and delete
 instance profiles instead. This feature will be removed from amazon.aws in a release after 2026-05-01. Deprecation warnings can be disabled by setting deprecation_warnings=False in 
ansible.cfg.
changed: [localhost]

TASK [Create a policy for s3 access] ********************************************************************
changed: [localhost]

TASK [ansible.builtin.debug] ****************************************************************************
ok: [localhost] => {
    "msg": {
        "changed": true,
        "diff": {
            "after": {
                "TransferFamilyS3AccessPolicy": {
                    "Statement": [
                        {
                            "Action": [
                                "s3:ListBucket",
                                "s3:GetBucketLocation"
                            ],
                            "Effect": "Allow",
                            "Resource": [
                                "arn:aws:s3:::advent-server"
                            ],
                            "Sid": "Statement1"
                        },
                        {
                            "Action": [
                                "s3:PutObject",
                                "s3:GetObject",
                                "s3:DeleteObject"
                            ],
                            "Effect": "Allow",
                            "Resource": "arn:aws:s3:::advent-server/*",
                            "Sid": "Statement2"
                        }
                    ],
                    "Version": "2012-10-17"
                }
            },
            "before": {}
        },
        "failed": false,
        "policy_names": [
            "TransferFamilyS3AccessPolicy"
        ],
        "role_name": "TransferFamilyS3AccessRole"
    }
}

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

$ 


登録の確認

作成したポリシーが、同じく作成したロールにアタッチされています。

$ aws iam list-role-policies --role-name TransferFamilyS3AccessRole
{
    "PolicyNames": [
        "TransferFamilyS3AccessPolicy"
    ]
}


その他

ansible11.0.0のデフォルトコレクション

$ ansible-galaxy collection list

# /home/ubuntu/.local/lib/python3.12/site-packages/ansible_collections
Collection                               Version
---------------------------------------- -------
amazon.aws                               9.0.0  
ansible.netcommon                        7.1.0  
ansible.posix                            1.6.2  
ansible.utils                            5.1.2  
ansible.windows                          2.5.0  
arista.eos                               10.0.1 
awx.awx                                  24.6.1 
azure.azcollection                       3.0.0  
check_point.mgmt                         6.2.1  
chocolatey.chocolatey                    1.5.3  
cisco.aci                                2.10.1 
cisco.asa                                6.0.0  
cisco.dnac                               6.22.0 
cisco.intersight                         2.0.20 
cisco.ios                                9.0.3  
cisco.iosxr                              10.2.2 
cisco.ise                                2.9.5  
cisco.meraki                             2.18.3 
cisco.mso                                2.9.0  
cisco.nxos                               9.2.1  
cisco.ucs                                1.14.0 
cloud.common                             4.0.0  
cloudscale_ch.cloud                      2.4.0  
community.aws                            9.0.0  
community.ciscosmb                       1.0.9  
community.crypto                         2.22.3 
community.digitalocean                   1.27.0 
community.dns                            3.0.7  
community.docker                         4.0.1  
community.general                        10.0.1 
community.grafana                        2.1.0  
community.hashi_vault                    6.2.0  
community.hrobot                         2.0.2  
community.library_inventory_filtering_v1 1.0.2  
community.libvirt                        1.3.0  
community.mongodb                        1.7.8  
community.mysql                          3.10.3 
community.network                        5.1.0  
community.okd                            4.0.0  
community.postgresql                     3.7.0  
community.proxysql                       1.6.0  
community.rabbitmq                       1.3.0  
community.routeros                       3.0.0  
community.sap_libs                       1.4.2  
community.sops                           2.0.0  
community.vmware                         5.1.0  
community.windows                        2.3.0  
community.zabbix                         3.1.2  
containers.podman                        1.16.2 
cyberark.conjur                          1.3.1  
cyberark.pas                             1.0.27 
dellemc.enterprise_sonic                 2.5.1  
dellemc.openmanage                       9.8.0  
dellemc.powerflex                        2.5.0  
dellemc.unity                            2.0.0  
f5networks.f5_modules                    1.32.1 
fortinet.fortimanager                    2.7.0  
fortinet.fortios                         2.3.8  
google.cloud                             1.4.1  
grafana.grafana                          5.6.0  
hetzner.hcloud                           4.2.1  
ibm.qradar                               4.0.0  
ibm.spectrum_virtualize                  2.0.0  
ibm.storage_virtualize                   2.5.0  
ieisystem.inmanage                       3.0.0  
infinidat.infinibox                      1.4.5  
infoblox.nios_modules                    1.7.0  
inspur.ispim                             2.2.3  
junipernetworks.junos                    9.1.0  
kaytus.ksmanage                          2.0.0  
kubernetes.core                          5.0.0  
kubevirt.core                            2.1.0  
lowlydba.sqlserver                       2.3.4  
microsoft.ad                             1.7.1  
netapp.cloudmanager                      21.24.0
netapp.ontap                             22.12.0
netapp.storagegrid                       21.13.0
netapp_eseries.santricity                1.4.1  
netbox.netbox                            3.20.0 
ngine_io.cloudstack                      2.5.0  
openstack.cloud                          2.2.0  
ovirt.ovirt                              3.2.0  
purestorage.flasharray                   1.31.1 
purestorage.flashblade                   1.19.1 
sensu.sensu_go                           1.14.0 
splunk.es                                4.0.0  
telekom_mms.icinga_director              2.2.0  
theforeman.foreman                       4.2.0  
vmware.vmware                            1.6.0  
vmware.vmware_rest                       4.2.0  
vultr.cloud                              1.13.0 
vyos.vyos                                5.0.0  
wti.remote                               1.0.10 


iam_roleモジュールの戻り値の変更

iam_role.assume_role_policy_document_rawは戻り値から削除される。

[DEPRECATION WARNING]: In a release after 2026-05-01 iam_role.assume_role_policy_document_raw will no longer be returned.  Since release 8.0.0 assume_role_policy_document has been 
returned with the same format as iam_role.assume_role_policy_document_raw. This feature will be removed from amazon.aws in a release after 2026-05-01. Deprecation warnings can be 
disabled by setting deprecation_warnings=False in ansible.cfg.


Playbookで作成したロールとポリシーを削除する

同じPlaybookを流用する場合の手順です。
ポリシーをabsentにして実行、ロールをabsentにして実行(ポリシーでエラーが出るが気にしない)します。
最後に、インスタンスプロファイルをコマンドで削除します。

aws iam delete-instance-profile --instance-profile-name TransferFamilyS3AccessRole
                                                        ↑プロファイル名(ここではロール名と同じ)

アーキテクチャConference2024参加メモ

はじめに

2024/11/26に、Findy主催の「アーキテクチャConference2024」に現地参加してきました。
その時のメモをまとめておきます。


アーキテクチャConference2024とは
 エンジニアリングを取り巻く環境の変化スピードは年々早くなり、組織・コスト・ツールなどアーキテクチャを構成する要素も多様化しています。企業やプロジェクトごとに異なるアーキテクチャの選定・開発には正解が存在しない一方で、開発者体験や品質向上の観点からもその重要性は増してきています。また、トレンドを追うだけではベストを作ることが難しいと言われています。
 本カンファレンスでは、ご登壇者の方々に今一度システムの基盤となるアーキテクチャの思考法や手法といった全体像から、他社が実践した具体的な構築事例といった部分像までをお話しいただくことで、アーキテクチャに対する考え方を学び直し、発想を広げられることを目指しています。


概要 architecture-con.findy-tools.io
登壇資料一覧 findy-tools.io

ブースメモ

各社サービスのアーキテクチャ図を、全体像やCICD、オブザーバビリティ等の観点から紹介。一通り写真を撮ったけど、公開して良いのかわからないので割愛。 アーキテクチャの選定理由をひたすら読めて参考になりました。
また、アンチパターンさんのブースでもらったSaaS開発ガイドがありがたかったです。テナントの概念を初めて知って、DBへの理解が深まりました。SaaS初心者にはぜひお勧めしたいなと。



セッションのメモ

いくつかのセッションメモを記載します。

ビジネスの成長を加速するB2B SaaSのスケーリングアーキテクチャ


3社と語るAWS Architecture レビュー会

  • 概要
  • SaaSusプラットフォームの紹介
    • saas管理(コントロールプレーン)+フロントエンド(アプリケーションプレーン)
    • Warm poolについて
      • 常時稼働中のインスタンスよりコストを抑えられる。必要なときにすぐ起動できる。
  • リーガルブレインの紹介
    • 作らない、持たない
    • 抽象度の高いサービスを選ぶ
    • 復旧の自動化について
  • Findy team+の紹介


ソフトウェア開発の複雑さに立ち向かう

  • 概要
    • ソフトウェアが広く使われる現代では、複雑で高品質なソフトウェアを時間や予算の制約内で開発することが困難です。ソフトウェア開発には決まった答えがなく、エンジニアは探索と発見を繰り返す終わりのない学習活動です。このセッションでは、4つの視点からエンジニアの学びと成長を考察します
  • メモ
    • 複雑さがますます複雑に
      • 予測しづらい(pagerdutyのイベントでも聞いた
    • 事業視点
      • 事業活動とソフトの変化が一体化
      • 事業活動が広範囲にデジタル化され、エンジニアも事業を考える
      • 事業活動の当事者として設計する
        • 世界地図は現場に役立たない
      • 事業視点で設計すると言うことは、競争優位で設計する
        • 利益をあげる=ソフトで売り上げ増、コスト削減=コスト最適化
      • 事業活動の連動性と設計を整合させる
        • アプリ間連携の最適化を事業視点で考える
      • 競争優位性を産み出すアプローチ
        • 事業の関心の分離とモジュール化の経験則
        • 事業視点のソフトウェアの設計をどう習得するか
      • 詳細



原 トリさん・matsさんが語る、システム設計の勘所

  • 概要
    • AWSに在籍されていた際に、数多くの企業やプロダクトのシステム設計に携わり、現在は事業会社で活躍している株式会社カミナシのCTO・原 トリさん、チューリング株式会社のテックリード・matsさんをお招きし、「システム設計の勘所」について今も昔も変わらない重要なポイントについてディスカッションします。
  • メモ
    • システム設計で今後も変わらない重要なこと
      • 何のためにいつまで必要か、運用できるか、自分達の取り巻く環境を考える。
      • Windowsエンジニアが多かったらWindows優先のように。自分のこだわりは最後。
    • 変化への対応が重要
      • 違和感を覚えたときに変えるのが大事
      • 違和感をどう言語化するか
    • サービスが延びていくなかでいつリアーキテクチャするか
      • だいたいファーストインプレッションは7割間違い
      • 文章に起こして、論理的に検証する
      • 生成AIに聞くのもあり


所感

懇親会にも参加し、他社さんともかなり話せました。DevRel担当の方にも経営層向けのアピールの仕方が聞けてありがたかったです。 今回のイベントも楽しかったので、来年もぜひ参加したいと思います。

[Terraform] 再作成や変更が起きない、動的属性をもつパラメータがある

本記事の内容は、公式ドキュメントに記載されているわけではなく、GitHubのissueを確認し検証した内容のため、正しくない可能性があります。

まとめ

Terraformには、再作成や変更が起きない、動的属性をもつパラメータがあります。
通常、毎回変わるパラメータには、ignore_changesを指定してtfstateの変更を無視させることがあります。 ここでいう「動的属性をもつパラメータ」とは、ignore_changesを指定しなくても、それ相当の動きをします。 動的属性をもつパラメータは、実リソースとtfstateに差分があったとしてもplanやapplyに影響しません(再作成や変更は行わない)。

例えば、AWS EC2のパブリックIPアドレスは動的属性として扱われています。
これにより、再起動してパブリックIPアドレスに変更があっても、再作成や変更のトリガーにはなりません。
terraform applyを実行すると、結果は0 added, 0 changed, 0 destroyed.となり、tfstateのパブリックIPアドレスが更新されます。

参考 github.com

github.com

検証

terraformで作成したEC2を停止→再起動してパブリックIPアドレスを変え、terraform planの結果やtfstateを確認します。

環境

OSは「Ubuntu 22.04.3 LTS」、Terraformは「v1.9.4」です。

terraformでEC2インスタンスを作る

以下のコードでEC2インスタンスを作ります。
リージョンやクレデンシャル情報は、環境変数にセットしておきます。

resource "aws_instance" "example" {
  ami           = "ami-06b21ccaeff8cd686" #東京リージョンのAmazonLinux2023AMI
  instance_type = "t2.micro"

  tags = {
    Name = "Example_terraform"
  }
}


terraform applyを実行し、tfstateを確認します。

{
  "version": 4,
  "terraform_version": "1.9.4",
(略)
            "public_dns": "ec2-13-230-98-202.ap-northeast-1.compute.amazonaws.com",
            "public_ip": "13.230.98.202",
(略)
  ],
  "check_results": null
}


EC2インスタンスを停止後、起動して差分を確認する

AWSコンソールで停止→起動してパブリックIPアドレスを変えました。
結果、terraform planで差分は出ませんでした。この時点で、tfstateと割り振られたパブリックIPアドレスは異なります。

$ terraform plan
aws_instance.example: Refreshing state... [id=i-049e024097907a1a5]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
$ 


terraform applyしても再作成されませんでした。
ただし、tfstateのパブリックIPアドレスが更新されていました。

$ terraform apply
aws_instance.example: Refreshing state... [id=i-049e024097907a1a5]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

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


0 added, 0 changed, 0 destroyed.であり、更新したことがわかるメッセージなどはありません。

$ diff terraform.tfstate terraform.tfstate.backup 
4c4
<   "serial": 5,
---
>   "serial": 4,
96,97c96,97
<             "public_dns": "ec2-43-207-112-92.ap-northeast-1.compute.amazonaws.com",
<             "public_ip": "43.207.112.92",
---
>             "public_dns": "ec2-13-230-98-202.ap-northeast-1.compute.amazonaws.com",
>             "public_ip": "13.230.98.202",


所感

tfファイルを変更していないのに再作成になる話(=tfstate更新)はよく聞くのですが、tfファイルを変更しておらず再作成や変更もないのにtfstateが更新されるパターンもあります。
Terraform Registryaws_instanceのpublic_ipにも記載はないので、いずれどこかに記載されたらありがたいなと思います。

Chromeのプロファイルで、AWSアカウントなどを使い分ける

メモ

複数のAWSアカウントやそれに伴うブックマークなどを使い分けるのに、Chromeのプロファイルが便利でした。

プロファイル作成時に、自動でブラウザの色も変えてくれるので、今どのプロファイルを開いているのかも区別つけやすいです。


プロファイルの切り替えも簡単です。



プロファイルの作り方

右上のアイコンをクリックし、追加を選択します。

他のプロファイルをメインとして作業するなら、2個目以降のプロファイルは「アカウント無しで続行」で良いかと思います。


プロファイル名と色を選択して完了です。