Secrets Manager Now Supports Cross-Account Replication, So I Tried It Out

Secrets Manager Now Supports Cross-Account Replication, So I Tried It Out

I tried AWS Secrets Manager cross-account replication with two accounts. With a KMS key set up and associated on the replica side, primary updates reached the replica in about a second, and promoting it made it a standalone secret.
2026.11.15

This page has been translated by machine translation. View original

Introduction

On November 13, 2026, AWS Secrets Manager added support for cross-account replication.

https://aws.amazon.com/jp/about-aws/whats-new/2026/11/secrets-manager-cross-account/

This feature synchronizes a primary secret to a replica in a different account. Because the replica uses a KMS key on the replica side, you can still read the replica even when the primary secret or the primary-side KMS key is unavailable.

This time, using two accounts, I tried setting up replication, propagating updates from the primary, the behavior when the permissions on the primary-side KMS key are removed, and disassociation and promotion.

Setup

I used AWS CLI 2.40.3. The region is ap-northeast-1. Both accounts are member accounts, and I specified --replica-restriction NoRestriction for the association. The primary secret is encrypted with a customer managed key (CMK) in the primary-side account.

Where to configure What to configure Result if missing
Key policy of the replica-side CMK Allow kms:Encrypt to the primary-side account The association is rejected with AccessDeniedException
Key policy of the primary-side CMK Allow kms:Decrypt to the replication role Replication becomes Failed when the primary is updated
Resource policy of the replica Attached automatically by Secrets Manager (you do not write it yourself) —

Replica side

In the replica-side account, create a CMK. The key policy at creation has just one statement that allows kms:* to the account root, and I saved it as replica-key-policy-initial.json.

aws --profile replica --region ap-northeast-1 kms create-key --description xacct-demo\ replica --tags TagKey=Name\,TagValue=xacct-demo-replica --policy file://replica-key-policy-initial.json

Next, create the replica by specifying the primary's ARN in --cross-account-primary-arn. No secret value is passed at creation.

aws --profile replica --region ap-northeast-1 secretsmanager create-secret --name xacct-demo-replica-secret --cross-account-primary-arn arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:xacct-demo-primary-secret-AbCdEf --kms-key-id arn:aws:kms:ap-northeast-1:123456789012:key/abcd1234-ab12-cd34-ef56-abcdef123456 --tags Key=Name\,Value=xacct-demo-replica

Before association, the replica's replication status is Pending and it has no value.

The replica's resource policy was attached by Secrets Manager at the time of create-secret. If you run get-resource-policy with the policy name cross-account-replication, the body is returned.

aws --profile replica --region ap-northeast-1 secretsmanager get-resource-policy --secret-id xacct-demo-replica-secret --policy-name cross-account-replication

I have unescaped the ResourcePolicy string so that it can be read as JSON.

{
  "Version" : "2012-10-17",
  "Statement" : [ {
    "Sid" : "CrossAccountReplication",
    "Effect" : "Allow",
    "Principal" : {
      "AWS" : "arn:aws:iam::111122223333:root"
    },
    "Action" : "secretsmanager:AcceptCrossAccountReplication",
    "Resource" : "*",
    "Condition" : {
      "ForAnyValue:StringEquals" : {
        "aws:InvokedBy" : "secretsmanager.amazonaws.com"
      },
      "ArnEquals" : {
        "secretsmanager:CrossAccountPrimaryARN" : "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:xacct-demo-primary-secret-AbCdEf"
      }
    }
  } ]
}

Finally, add a kms:Encrypt permission for the primary-side account to the key policy of the replica-side CMK. Since the condition contains the replica's ARN, run this after creating the replica. Because put-key-policy replaces the entire key policy, replica-key-policy.json also includes the account root permission.

replica-key-policy.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EnableIAMPolicies",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::123456789012:root" },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "AllowCrossAccountReplication",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "kms:Encrypt",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:CallerAccount": "111122223333",
          "kms:EncryptionContext:SecretARN": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:xacct-demo-replica-secret-GhIjKl"
        }
      }
    }
  ]
}
aws --profile replica --region ap-northeast-1 kms put-key-policy --key-id arn:aws:kms:ap-northeast-1:123456789012:key/abcd1234-ab12-cd34-ef56-abcdef123456 --policy-name default --policy file://replica-key-policy.json

Primary side

In the primary-side account, create the replication role. The role's permissions policy allows only kms:Encrypt on the replica-side CMK, and I placed the kms:Decrypt permission only in the key policy of the primary-side CMK.

Replication role definition

role-trust.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "secretsmanager.amazonaws.com" },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": { "aws:SourceAccount": "111122223333" }
      }
    }
  ]
}

role-permissions.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EncryptReplicaSecretKey",
      "Effect": "Allow",
      "Action": "kms:Encrypt",
      "Resource": "arn:aws:kms:ap-northeast-1:123456789012:key/abcd1234-ab12-cd34-ef56-abcdef123456",
      "Condition": {
        "StringEquals": { "kms:EncryptionContext:SecretARN": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:xacct-demo-replica-secret-GhIjKl" }
      }
    }
  ]
}
aws --profile primary --region ap-northeast-1 iam create-role --role-name xacct-demo-replication-role --assume-role-policy-document file://role-trust.json
aws --profile primary --region ap-northeast-1 iam put-role-policy --role-name xacct-demo-replication-role --policy-name replication --policy-document file://role-permissions.json

Add a kms:Decrypt permission for the role to the key policy of the primary-side CMK. Here too, replace it with the full text including the account root permission.

primary-key-policy.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EnableIAMPolicies",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::111122223333:root" },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "AllowReplicationRoleDecrypt",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::111122223333:role/xacct-demo-replication-role" },
      "Action": "kms:Decrypt",
      "Resource": "*",
      "Condition": {
        "StringEquals": { "kms:EncryptionContext:SecretARN": "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:xacct-demo-primary-secret-AbCdEf" }
      }
    }
  ]
}
aws --profile primary --region ap-northeast-1 kms put-key-policy --key-id arn:aws:kms:ap-northeast-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab --policy-name default --policy file://primary-key-policy.json

Association

The association is performed from the primary-side account with associate-cross-account-replica. The IAM permissions required for the operator are described in the API reference. In this article, I ran it with administrator permissions.

https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_AssociateCrossAccountReplica.html

aws --profile primary --region ap-northeast-1 secretsmanager associate-cross-account-replica --secret-id xacct-demo-primary-secret --cross-account-replica-arn arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:xacct-demo-replica-secret-GhIjKl --replication-role-arn arn:aws:iam::111122223333:role/xacct-demo-replication-role --replica-restriction NoRestriction

After running it, the association started.

"ReplicationStatus": "InProgress"

Before reading the value, confirm that both sides are InSync with describe-secret.

Primary side:

"CrossAccountReplicas": [
    {
        "ReplicaSecretARN": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:xacct-demo-replica-secret-GhIjKl",
        "ReplicationRoleARN": "arn:aws:iam::111122223333:role/xacct-demo-replication-role",
        "ReplicationStatus": "InSync"
    }
]

Replica side:

"CrossAccountPrimary": {
    "PrimarySecretARN": "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:xacct-demo-primary-secret-AbCdEf",
    "ReplicationStatus": "InSync"
}

After it became InSync, running get-secret-value in the replica-side account returned the value. The VersionId is the same as the VersionId returned when the primary was created.

"VersionId": "EXAMPLE-VERSION-V1",
"SecretString": "value-v1",

Only one replica can be associated with one primary.

Replication behavior

Propagating updates

I updated the primary with put-secret-value and measured twice how long it took until get-secret-value in the replica-side account returned the new value. The start point is immediately before the put-secret-value call, and the end point is the time the replica returned the new value. In both cases the new value was returned on the first read, so the values in the table are upper bounds on the time the propagation took.

Update Start End Start to end
value-v2 11:53:00.383Z 11:53:01.393Z about 1.01 seconds
value-v3 11:53:09.431Z 11:53:10.389Z about 0.96 seconds

When the permissions on the primary-side CMK are removed

I removed the kms:Decrypt permission for the replication role from the key policy of the primary-side CMK, returning it to a state with only the account root permission (primary-key-policy-initial.json).

aws --profile primary --region ap-northeast-1 kms put-key-policy --key-id arn:aws:kms:ap-northeast-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab --policy-name default --policy file://primary-key-policy-initial.json

In that state, I updated the primary to value-v4 and checked the replication status and the replica's value.

Point in time Replication status Replica's get-secret-value
Immediately after removing the permission Replica InSync value-v3
About 15 seconds after updating to value-v4 Failed on both sides value-v3
About 5 seconds after restoring the permission and re-running the association Primary InSync value-v4

Even with the permission removed, put-secret-value on the primary and get-secret-value on the replica succeeded. Only replication failed, and the primary-side StatusMessage is as follows.

"StatusMessage": "Replication failed: User: arn:aws:sts::111122223333:assumed-role/xacct-demo-replication-role/SecretsManagerCrossAccountReplication-123456789012 is not authorized to perform: kms:Decrypt on resource: arn:aws:kms:ap-northeast-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab because no identity-based policy allows the kms:Decrypt action (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: <Request ID>; Proxy: null)"

The replica-side StatusMessage was Replication failed in the primary account.

Disassociation and promotion

State by operation

To stop replication, there are disassociate-cross-account-replica on the primary side and stop-replication-to-replica on the replica side.

aws --profile primary --region ap-northeast-1 secretsmanager disassociate-cross-account-replica --secret-id xacct-demo-primary-secret --cross-account-replica-arn arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:xacct-demo-replica-secret-GhIjKl
aws --profile replica --region ap-northeast-1 secretsmanager stop-replication-to-replica --secret-id xacct-demo-replica-secret-2

I ran each operation on an InSync replica and summarized the results in the following table. Since only one replica can be associated with one primary, after disassociating from the primary side, I created and associated a second replica and tried the replica-side operation.

Item checked Primary side disassociate-cross-account-replica Replica side stop-replication-to-replica
describe-secret of the primary CrossAccountReplicas disappears CrossAccountReplicas remains with Detached and Replication removed by the replica secret
describe-secret of the replica Detached and Replication removed by the primary secret CrossAccountPrimary disappears
put-secret-value on the replica Rejected Succeeds

With either operation, subsequent updates to the primary do not reach the replica.

State after promotion

When I ran stop-replication-to-replica on the first replica, which had become Detached through the primary-side disassociation, the replica was promoted. After promotion, get-secret-value returned value-v4 and put-secret-value succeeded. The resource policy for replication was also gone.

When promoted from the replica side, a record of the Detached replica remains on the primary. To remove the record, run disassociate-cross-account-replica on the primary side.

aws --profile primary --region ap-northeast-1 secretsmanager disassociate-cross-account-replica --secret-id xacct-demo-primary-secret --cross-account-replica-arn arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:xacct-demo-replica-secret-2-MnOpQr

Summary

I set up cross-account replication for Secrets Manager and was able to confirm the behavior of the replica.

Even if the secret or CMK in the primary-side account becomes unreadable due to ransomware damage, cross-account replication may allow you to restore the secret.

The aws-samples repository published a mechanism that copies secrets using Lambda and EventBridge, but this is now available as a Secrets Manager feature.

https://github.com/aws-samples/aws-secrets-manager-cross-account-backup

https://dev.classmethod.jp/articles/secrets-manager-cross-account-backup/

If you use Secrets Manager automatic rotation and the like, the value after rotation cannot be reproduced from elsewhere. Please make use of this as a safeguard against the risk of losing access to your secrets.

Share this article

AWSのお困り事はクラスメソッドへ