mito’s blog

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

[Terraform][AWS]Terraformで作成したSecrets ManagerとParameter Storeのtfstateにおける違い

結論

terraformで以下のリソースを作成し、手動などでシークレットの値を更新した後、再度terraformコマンドを実行すると、

  • Secrets Manager
    • terraform refreshをしても、tfstateに変更はありません。
    • terraform applyをしても、changedになりません。
  • Parameter Store
    • terraform refreshをすると、tfstateが更新されます。
    • terraform applyをすると、changedになります。



はじめに

Terraformで作成したSecretsManagerとParameterStoreのそれぞれの値について、tfstateでの管理に差異があったので書き留めておきます。

Resource: aws_secretsmanager_secret

Resource: aws_ssm_parameter


リソース:aws_secretsmanager_secret

シークレットマネージャは、AWSマネジメントコンソールからは即削除できませんが、
Terraformではrecovery_window_in_days = 0を設定することで即削除できます。

recovery_window_in_days - (Optional) Number of days that AWS Secrets Manager waits before it can delete the secret. This value can be 0 to force deletion without recovery or range from 7 to 30 days. The default value is 30.


SecretsManager作成のTFファイル

シークレット名web_passwordを作成し、key:valuepassword:test1234を登録します。

resource "aws_secretsmanager_secret" "asm_secret_web" {
  name = "web_password"
  recovery_window_in_days = 0
}

resource "aws_secretsmanager_secret_version" "asm_secret_web_version" {
  secret_id     = aws_secretsmanager_secret.asm_secret_web.id
  secret_string = jsonencode({"password" = "test1234"})
}


terraform applyの実行

terraform applyを実行し、シークレットマネージャにリソースを作成します。

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

()

Plan: 2 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

aws_secretsmanager_secret.asm_secret_web: Creating...
aws_secretsmanager_secret.asm_secret_web: Creation complete after 1s [id=arn:aws:secretsmanager:ap-northeast-1:*****:secret:web_password-7fD0bZ]
aws_secretsmanager_secret_version.asm_secret_web_version: Creating...
aws_secretsmanager_secret_version.asm_secret_web_version: Creation complete after 0s [id=arn:aws:secretsmanager:ap-northeast-1:*****:secret:web_password-7fD0bZ|********]

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


tfstateには、以下が記載されています。

"name": "web_password",
"secret_string": "{\"password\":\"test1234\"}",


passwordの書き換え

ansibleでpasswordをtest1234から、oioioioioiに更新します。

Playbook例
[Ansible][AWS] SecretsManagerモジュールでユーザとパスワードを登録する(更新2023.02.13) - mito’s blog

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

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

TASK [debug] ***************************************************************
ok: [localhost] => {
    "msg": {
        "password": "test1234"
    }
}

TASK [Update Secrets Manager] *************************************************
changed: [localhost]

TASK [debug] ***************************************************************
ok: [localhost] => {
    "msg": {
        "password": "oioioioioi"
    }
}

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

$ 


terraform apply -refresh-onlyの実行

terraform apply -refresh-onlyを実行しても、tfstateには変更ありません。

$ terraform apply -refresh-only
aws_secretsmanager_secret.asm_secret_web: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:*****:secret:web_password-7fD0bZ]
aws_secretsmanager_secret_version.asm_secret_web_version: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:*****:secret:web_password-7fD0bZ|********]

No changes. Your infrastructure still matches the configuration.

Terraform has checked that the real remote objects still match the result of your most recent changes, and found no differences.

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


tfstateのpasswordは、test1234のままです。

"secret_string": "{\"password\":\"test1234\"}",


terraform applyの実行

terraform applyの実行でも変更はありません。

$ terraform apply
aws_secretsmanager_secret.asm_secret_web: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:*****:secret:web_password-7fD0bZ]
aws_secretsmanager_secret_version.asm_secret_web_version: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:*****:secret:web_password-7fD0bZ|********]

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.
$


リソース:ssm_parameter

ParameterStore作成のTFファイル

パラメータ名web_passwordを作成し、valuetest1234を登録します。

resource "aws_ssm_parameter" "ssm_parameter_web_password" {
  name        = "web_password"
  type        = "SecureString"
  value       = "tes1234"
}


terraform applyの実行

terraform applyを実行し、パラメータストアにリソースを作成します。

$ terraform apply

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

()

Plan: 1 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

aws_ssm_parameter.ssm_parameter_web_password: Creating...
aws_ssm_parameter.ssm_parameter_web_password: Creation complete after 0s [id=web_password]

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


tfstateには、以下が記載されています。

"name": "web_password",
"value": "tes1234",


passwordの書き換え

ansibleでpasswordをtest1234から、oioioioioiに更新します。

Playbook例
[Ansible][AWS] ParameterStoreモジュールでユーザとパスワードを登録する - mito’s blog

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

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

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "tes1234"
}

TASK [Update SSM parameter store] ************************
changed: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "oioioioi"
}

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

$ 


terraform apply -refresh-onlyの実行

terraform apply -refresh-onlyを実行すると、tfstateに変更が入ります。
また、-refresh-onlyを付けているためapplyは実行しておらず、0 changedになります。

$ terraform apply -refresh-only
aws_ssm_parameter.ssm_parameter_web_password: Refreshing state... [id=web_password]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply":

  # aws_ssm_parameter.ssm_parameter_web_password has changed
  ~ resource "aws_ssm_parameter" "ssm_parameter_web_password" {
        id        = "web_password"
        name      = "web_password"
      + tags      = {}
      ~ value     = (sensitive value)
      ~ version   = 1 -> 2
        # (6 unchanged attributes hidden)
    }


This is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can
apply this plan to record the updated values in the Terraform state without changing any remote objects.

Would you like to update the Terraform state to reflect these detected changes?
  Terraform will write these changes to the state without modifying any real infrastructure.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes


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


tfstateには、差分が見受けられます。
passwordやversionが更新されています。

$ diff -u terraform.tfstate.backup terraform.tfstate                                     
--- terraform.tfstate.backup    2023-03-04 21:22:36.243115094 +0900
+++ terraform.tfstate   2023-03-04 21:22:36.243115094 +0900
@@ -1,7 +1,7 @@
-  "serial": 8,
+  "serial": 9,
@@ -23,12 +23,12 @@
-            "tags": null,
+            "tags": {},
-            "value": "tes1234",
-            "version": 1
+            "value": "oioioioi",
+            "version": 2


terraform applyの実行

terraform applyを実行すると、passwordが書き換え前に変更されます。

$ terraform apply
aws_ssm_parameter.ssm_parameter_web_password: Refreshing state... [id=web_password]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_ssm_parameter.ssm_parameter_web_password will be updated in-place
  ~ resource "aws_ssm_parameter" "ssm_parameter_web_password" {
        id             = "web_password"
      + insecure_value = (known after apply)
        name           = "web_password"
        tags           = {}
      ~ value          = (sensitive value)
      ~ version        = 2 -> (known after apply)
        # (6 unchanged attributes hidden)
    }

Plan: 0 to add, 1 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

aws_ssm_parameter.ssm_parameter_web_password: Modifying... [id=web_password]
aws_ssm_parameter.ssm_parameter_web_password: Modifications complete after 0s [id=web_password]

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


passwordが書き換える前の値(TFファイルの値)に変わりました。

$ diff -u terraform.tfstate.backup terraform.tfstate
--- terraform.tfstate.backup    2023-03-04 21:29:22.879912086 +0900
+++ terraform.tfstate   2023-03-04 21:29:22.895912433 +0900
@@ -1,7 +1,7 @@
-  "serial": 9,
+  "serial": 11,
@@ -27,8 +27,8 @@
-            "value": "oioioioi",
-            "version": 2
+            "value": "tes1234",
+            "version": 3
$ 


備考

Secrets ManagerとParameter Storeのどちらを使用するかは、運用に応じて選択するのが良いかと思います。
ただし、terraform外での値の変更が予想される場合には、terraform applyの実行では値が変更されないSecretsManagerをお勧めします。課金されるけど。