Sharing Secrets Across an AWS Organization with SSM Parameter Store and Secrets Manager: RAM, KMS, and Regional Replication
A security agent baked into a golden Amazon Machine Image (AMI) often needs a registration token when a new Amazon EC2 instance first boots. The same problem appears with third-party license keys, package-repository credentials, webhook signing keys, and bootstrap credentials for shared internal services. The value is centrally governed, but workloads in many AWS accounts and AWS Regions must retrieve it without making it public, copying it into an AMI, or maintaining an unbounded list of account IDs.
AWS Systems Manager Parameter Store and AWS Secrets Manager can both provide this capability. Their architectures are not interchangeable, however. Cross-account authorization, encryption, resource discovery, regional availability, rotation, service integrations, quotas, and billing differ in ways that only become obvious when the complete access path is exercised.
This article builds and tests both designs. It uses only AWS CLI examples, anonymized identifiers, and synthetic secret values. The intended reader already understands IAM, AWS Organizations, AWS Key Management Service (AWS KMS), and regional AWS service endpoints.
Executive recommendation
Treat cross-account authorization and cross-Region availability as separate design problems:
- Use Secrets Manager when the value is a true secret that benefits from managed rotation, native same-account regional replication, larger values, or broader service integrations.
- Use Parameter Store Advanced parameters when the value is relatively static, no larger than 8 KB, the supported integrations are sufficient, and the platform team is prepared to own cross-Region replication and reconciliation.
- Prefer per-account, per-environment, or per-site credentials over one organization-wide credential. If the external control plane supports AWS identity attestation or short-lived registration credentials, use that instead of distributing a static shared secret.
- Never bake the secret into an AMI. Bake only nonsecret lookup metadata—such as a parameter ARN, secret ARN, or site identifier—and retrieve the value at first boot with the EC2 instance role.
For a registration-token use case with three security domains—for example, US production, US non-production, and international—create at least three tokens and scope each token to the corresponding OUs and workload roles. A rarely rotated token is still a bearer credential; segmentation limits the impact of disclosure and simplifies revocation.
| Decision factor | SSM Parameter Store | Secrets Manager |
|---|---|---|
| Cross-account mechanism | AWS Resource Access Manager (AWS RAM), backed by a parameter resource policy | Secret resource policy; Secrets Manager is not shared through RAM |
| Shareable tier | Advanced only | All secrets, subject to policy and KMS requirements |
| Cross-account encryption | Customer-managed KMS key required | Customer-managed KMS key required |
| Native cross-Region replication | No | Yes, within the same AWS account |
| Rotation | Custom | Managed rotation for supported services or Lambda-based rotation |
| Maximum value size | 8 KB for Advanced | 65,536 bytes |
| Consumer lookup | Full parameter ARN | Full secret ARN |
| Hierarchical retrieval of shared resources | GetParametersByPath is not in the RAM permissions |
Not applicable |
| Base storage price in US Regions | USD 0.05 per Advanced parameter-month | USD 0.40 per secret-month; every replica is another billed secret |
| Best fit | Relatively static bootstrap values and configuration | Credentials with lifecycle, rotation, or regional-resilience requirements |
Prices and quotas change. Verify the linked AWS service pages before making a production cost decision.
First question: should this be one shared secret?
Central storage does not make a broadly shared bearer token low risk. If every workload in an organization receives the same token, compromise of one workload can expose a credential valid everywhere. Rotation also becomes an organization-wide event.
Evaluate alternatives in this order:
- AWS identity attestation or federation. The external system validates a signed AWS identity or an assumed role instead of accepting a static token.
- One-time bootstrap credentials. A narrowly authorized broker exchanges AWS identity for a short-lived, single-use registration credential.
- Per-account, per-environment, or per-site tokens. A compromised non-production token cannot register production workloads.
- One organization-wide static token. Use only when the control plane cannot support a narrower model, and document the resulting blast radius.
The storage service cannot compensate for an over-broad credential. Parameter Store and Secrets Manager control who can retrieve the token; they do not restrict what a caller can do after retrieving it.
The four gates in a cross-account read
A successful read from another AWS account must pass four independent gates:
- Consumer identity authorization. The workload role needs
ssm:GetParameterorsecretsmanager:GetSecretValue, pluskms:Decryptfor the owner account’s KMS key. - Resource-side authorization. Parameter Store uses a RAM share/resource policy. Secrets Manager uses a resource policy attached to the secret.
- KMS authorization. The owner account’s KMS key policy must permit the external principal, and the external principal’s IAM policy must delegate the corresponding KMS permission.
- Regional routing. The AWS CLI or SDK client must call the endpoint in the Region encoded in the resource ARN. An ARN does not cause an AWS service endpoint to route the request to another Region.
An SCP, permissions boundary, session policy, VPC endpoint policy, or explicit deny can still reject the request after these allows are present.

The examples in this article use the following anonymized values:
export ORG_MANAGEMENT_ACCOUNT_ID="999900001111"
export SECRET_OWNER_ACCOUNT_ID="111122223333"
export CONSUMER_ACCOUNT_ID="444455556666"
export ORG_ID="o-a1b2c3d4e5"
export ROOT_ID="r-abcd"
export TARGET_OU_ID="ou-abcd-12345678"
export PRIMARY_REGION="us-east-1"
export REPLICA_REGION="us-west-2"
export OWNER_PROFILE="secret-owner"
export CONSUMER_PROFILE="workload"
export ORG_PROFILE="org-management"
export PARAMETER_NAME="/org/bootstrap/security-agent/registration-token"
export SECRET_NAME="org/bootstrap/security-agent/registration-token"
The profile names are local AWS CLI profiles. They are not IAM principals and do not appear in policies.
Establish the AWS Organizations and RAM prerequisite
Sharing a parameter with an organization or OU requires RAM integration with AWS Organizations. Enable it once from the Organizations management account:
aws ram enable-sharing-with-aws-organization \
--profile "${ORG_PROFILE}" \
--region "${PRIMARY_REGION}"
This creates the AWSServiceRoleForResourceAccessManager service-linked role. Verify it without changing the configuration:
aws iam get-role \
--profile "${ORG_PROFILE}" \
--role-name AWSServiceRoleForResourceAccessManager \
--query 'Role.[Arn,CreateDate]' \
--output table
When Organizations sharing is enabled, principals inside the organization do not accept RAM invitations. External-account shares use a different trust workflow and are outside this article’s scope.
Construct the organization and OU principal ARNs with the Organizations management account ID, not the resource owner’s account ID:
export ORGANIZATION_ARN="arn:aws:organizations::${ORG_MANAGEMENT_ACCOUNT_ID}:organization/${ORG_ID}"
export TARGET_OU_ARN="arn:aws:organizations::${ORG_MANAGEMENT_ACCOUNT_ID}:ou/${ORG_ID}/${TARGET_OU_ID}"
Build regional KMS keys before sharing either service
The default keys aws/ssm and aws/secretsmanager are AWS managed keys. Their policies cannot be edited, so they cannot authorize a principal in another account. Cross-account retrieval therefore requires a customer-managed KMS key in every Region that contains a parameter or secret.
Create a symmetric key in the primary Region:
export PRIMARY_KEY_ID=$(
aws kms create-key \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--description "Shared bootstrap secrets - ${PRIMARY_REGION}" \
--key-usage ENCRYPT_DECRYPT \
--key-spec SYMMETRIC_DEFAULT \
--origin AWS_KMS \
--tags \
TagKey=Purpose,TagValue=SharedBootstrapSecrets \
TagKey=Environment,TagValue=Example \
--query 'KeyMetadata.KeyId' \
--output text
)
export PRIMARY_KEY_ARN=$(
aws kms describe-key \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--key-id "${PRIMARY_KEY_ID}" \
--query 'KeyMetadata.Arn' \
--output text
)
aws kms create-alias \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--alias-name alias/shared-bootstrap-secrets \
--target-key-id "${PRIMARY_KEY_ID}"
A production key policy should preserve key administration and restrict external use by organization, service, Region, and encryption context. The following policy illustrates one regional key serving the two example resource prefixes. Separate keys per service or security domain provide stronger isolation at additional cost and operational complexity.
{
"Version": "2012-10-17",
"Id": "shared-bootstrap-secrets-us-east-1",
"Statement": [
{
"Sid": "EnableOwnerAccountIAMPermissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "AllowOrganizationParameterDecryptThroughSSM",
"Effect": "Allow",
"Principal": "*",
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-a1b2c3d4e5",
"kms:ViaService": "ssm.us-east-1.amazonaws.com"
},
"StringLike": {
"kms:EncryptionContext:PARAMETER_ARN": "arn:aws:ssm:us-east-1:111122223333:parameter/org/bootstrap/*"
}
}
},
{
"Sid": "AllowOrganizationSecretDecryptThroughSecretsManager",
"Effect": "Allow",
"Principal": "*",
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-a1b2c3d4e5",
"kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
},
"StringLike": {
"kms:EncryptionContext:SecretARN": "arn:aws:secretsmanager:us-east-1:111122223333:secret:org/bootstrap/*"
}
}
}
]
}
Save this as kms-key-policy-us-east-1.json, review it through the organization’s normal change process, and apply it:
aws kms put-key-policy \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--key-id "${PRIMARY_KEY_ID}" \
--policy-name default \
--policy file://kms-key-policy-us-east-1.json
Do not blindly replace an existing key policy. Preserve designated key administrators, break-glass access, and any controls required by the organization. The account-root statement in this example delegates key management to IAM policies in the owner account; it does not give every identity automatic access.
The two external-use statements use different encryption-context keys:
- Parameter Store supplies
PARAMETER_ARN. - Secrets Manager supplies
SecretARN.
Both statements use kms:ViaService, so the permission cannot be used for a direct kms:Decrypt request. They also use aws:PrincipalOrgID; principals that leave the organization stop matching the condition. The consumer still needs an IAM allow for the exact KMS key.
Create an independent key and equivalent regional policy in us-west-2 before creating regional copies. A primary key’s policy is never a substitute for a replica Region’s key policy.
Grant the consumer role its side of the authorization
Assume an existing workload role named SharedSecretReader. Attach only the service and KMS actions it needs. Use the exact ARNs returned by resource creation; the secret ARN includes a six-character suffix.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadSharedParameter",
"Effect": "Allow",
"Action": [
"ssm:GetParameter",
"ssm:GetParameters"
],
"Resource": "arn:aws:ssm:us-east-1:111122223333:parameter/org/bootstrap/security-agent/registration-token"
},
{
"Sid": "ReadSharedSecret",
"Effect": "Allow",
"Action": [
"secretsmanager:DescribeSecret",
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:org/bootstrap/security-agent/registration-token-AbCdEf"
},
{
"Sid": "DecryptSharedValues",
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:us-east-1:111122223333:key/12345678-1234-1234-1234-123456789012"
}
]
}
Save it as shared-secret-reader-policy.json and attach it in the consumer account:
aws iam put-role-policy \
--profile "${CONSUMER_PROFILE}" \
--role-name SharedSecretReader \
--policy-name ReadCentralBootstrapSecrets \
--policy-document file://shared-secret-reader-policy.json
Repeat with the replica Region’s parameter, secret, and KMS key ARNs when local regional copies exist. Wildcarding the account, Region, or complete secret path makes future operations easier but expands the blast radius. Prefer generating exact policies from an approved inventory.
Option 1: share an SSM Parameter Store SecureString
Create an Advanced SecureString
Parameter Store supports cross-account sharing only for Advanced parameters. The value must use a customer-managed KMS key.
Avoid putting a production value directly into shell history. For a controlled administrative session, disable tracing, read the value silently, and clear the variable immediately after the request:
set +x
read -r -s -p "Synthetic test token: " REGISTRATION_TOKEN
printf '\n'
aws ssm put-parameter \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--name "${PARAMETER_NAME}" \
--description "Security agent bootstrap token" \
--type SecureString \
--tier Advanced \
--key-id "${PRIMARY_KEY_ARN}" \
--value "${REGISTRATION_TOKEN}" \
--tags \
Key=Purpose,Value=SecurityAgentBootstrap \
Key=SecurityDomain,Value=USNonProduction
unset REGISTRATION_TOKEN
The secret is still briefly present in the local process environment and AWS CLI argument memory. For production provisioning, inject it from an approved secrets workflow on a hardened runner rather than typing it interactively.
Get the canonical ARN:
export PARAMETER_ARN=$(
aws ssm get-parameter \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--name "${PARAMETER_NAME}" \
--query 'Parameter.ARN' \
--output text
)
An Advanced SecureString uses envelope encryption. Parameter Store generates a data key, encrypts the value with that data key, and encrypts the data key under the configured KMS key. The parameter ARN is cryptographically bound through the PARAMETER_ARN encryption context.
Explicit sharing through RAM: the recommended path
Create a resource share for the target OU. Specifying the managed permission explicitly makes the history decision visible in review:
export PARAMETER_SHARE_ARN=$(
aws ram create-resource-share \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--name shared-security-agent-token-us-nonprod \
--resource-arns "${PARAMETER_ARN}" \
--principals "${TARGET_OU_ARN}" \
--permission-arns \
arn:aws:ram::aws:permission/AWSRAMDefaultPermissionSSMParameterReadOnly \
--no-allow-external-principals \
--query 'resourceShare.resourceShareArn' \
--output text
)
RAM accepts the request before every asynchronous association has necessarily completed. Check the resource and principal associations:
aws ram get-resource-share-associations \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--association-type RESOURCE \
--resource-share-arns "${PARAMETER_SHARE_ARN}" \
--query 'resourceShareAssociations[].{Resource:associatedEntity,Status:status,Message:statusMessage}' \
--output table
aws ram get-resource-share-associations \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--association-type PRINCIPAL \
--resource-share-arns "${PARAMETER_SHARE_ARN}" \
--query 'resourceShareAssociations[].{Principal:associatedEntity,Status:status,Message:statusMessage}' \
--output table
A resource share can target an individual account ID, an OU ARN, or the organization ARN. Prefer the narrowest stable boundary. OU sharing adapts as accounts move into or out of the OU, but account movement is therefore an access-control event that should be monitored and reviewed.
Choose whether consumers may read history
Parameter Store exposes two RAM managed permissions:
| RAM permission | Allowed SSM actions |
|---|---|
AWSRAMDefaultPermissionSSMParameterReadOnly |
DescribeParameters, GetParameter, GetParameters |
AWSRAMPermissionSSMParameterReadOnlyWithHistory |
The default actions plus GetParameterHistory |
A previous token version can remain valid in an external control plane even after Parameter Store is updated. Grant history only when consumers have an explicit operational requirement for old values.
List the currently available permissions instead of hard-coding assumptions:
aws ram list-permissions \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--resource-type ssm:Parameter \
--query 'permissions[].{Name:name,Arn:arn,Version:version,Default:isResourceTypeDefault}' \
--output table
Neither permission includes GetParametersByPath. Shared Parameter Store hierarchies cannot be consumed as if they were a local recursive namespace. Share and retrieve explicit parameter ARNs.
Retrieve the shared parameter
The consuming account must use the full owner-account ARN:
aws ssm get-parameter \
--profile "${CONSUMER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--name "${PARAMETER_ARN}" \
--with-decryption \
--query 'Parameter.Value' \
--output text
Using only /org/bootstrap/security-agent/registration-token makes the service search the consumer account and returns ParameterNotFound.
Shared parameters are not shown as the consumer’s own parameters. With an explicit RAM share—or a promoted implicit share—the consumer can inventory them with:
aws ssm describe-parameters \
--profile "${CONSUMER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--shared \
--query 'Parameters[].{Name:Name,Type:Type,Tier:Tier,Version:Version}' \
--output table
Without --with-decryption, GetParameter can return the encrypted envelope to an authorized SSM caller even if that caller cannot use the KMS key. That does not expose plaintext, but it demonstrates why SSM authorization and KMS authorization are separate controls.
Implicit sharing with PutResourcePolicy
Parameter Store also supports attaching a resource policy directly. This creates a RAM resource share with featureSet set to CREATED_FROM_POLICY.
A policy intended to match the default RAM permission must contain all three actions:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowConsumerAccountRead",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::444455556666:root"
},
"Action": [
"ssm:DescribeParameters",
"ssm:GetParameter",
"ssm:GetParameters"
],
"Resource": "arn:aws:ssm:us-east-1:111122223333:parameter/org/bootstrap/security-agent/registration-token"
}
]
}
The SSM PutResourcePolicy API expects the policy as a nonempty string. Load the JSON with Bash command substitution before passing it; command substitution removes trailing newlines and avoids the trailing-newline validation behavior observed in CLI testing without adding another command-line dependency:
export SSM_RESOURCE_POLICY="$(<ssm-parameter-resource-policy.json)"
aws ssm put-resource-policy \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--resource-arn "${PARAMETER_ARN}" \
--policy "${SSM_RESOURCE_POLICY}" \
--query '[PolicyId,PolicyHash]' \
--output table
unset SSM_RESOURCE_POLICY
The consumer can retrieve the parameter by full ARN immediately, but the parameter does not appear in describe-parameters --shared, and RAM’s normal consumer inventory does not expose it yet. Promote the policy-created share to a standard share:
aws ram get-resource-shares \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--resource-owner SELF \
--query "resourceShares[?featureSet=='CREATED_FROM_POLICY' && status=='ACTIVE'].{Arn:resourceShareArn,Name:name}" \
--output table
aws ram promote-resource-share-created-from-policy \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--resource-share-arn "arn:aws:ram:us-east-1:111122223333:resource-share/EXAMPLE"
Identify the share by its resource association rather than selecting the first result in an account with multiple implicit shares.
In my testing, promotion failed with UnmatchedPolicyPermissionException when the custom policy allowed only GetParameter and GetParameters. Adding DescribeParameters made the action set match AWSRAMDefaultPermissionSSMParameterReadOnly, after which promotion succeeded. Updating the policy replaced the policy-created RAM share ARN, so automation must rediscover the active share before promotion.
Use explicit RAM shares unless an existing policy-management workflow requires PutResourcePolicy. Explicit shares are easier to discover, review, and operate.
Parameter Store is regional and has no native replication
Calling the us-west-2 SSM endpoint with a us-east-1 parameter ARN fails with an incorrect-Region validation error. A workload in us-west-2 has two choices:
- Deliberately call the
us-east-1endpoint and accept the cross-Region dependency, latency, and data-transfer path. - Read a separately created
us-west-2parameter encrypted under aus-west-2KMS key and shared through aus-west-2RAM share.
Parameter Store does not synchronize those resources. In my testing, updating the east parameter to version 3 left the independently created west parameter at version 1.
A production replication mechanism therefore needs more than an EventBridge rule:
- Parameter-change events are best effort.
- The replicator must fetch the source value with decryption and write it with the destination Region’s KMS key.
- The destination needs its own tags, policies, KMS policy, and RAM share.
- Replication must be idempotent and must prevent update loops.
- A scheduled reconciler must compare approved source versions or hashes against every destination, repairing missed events.
- Replication state and failures need alarms.
- The primary Region and conflict policy must be explicit; do not allow independent writes in every Region.
Do not implement replication by placing plaintext values on an EventBridge event bus. Events and CloudTrail records are not secret-transport channels.
Shared-parameter integration constraints
AWS supports shared parameters in these integrations:
- CloudFormation template parameters
- AWS Parameters and Secrets Lambda Extension
- EC2 launch templates
ImageIdvalues supplied to EC2RunInstances- Systems Manager Automation runbooks
AWS does not support shared parameters in these scenarios:
- Systems Manager Run Command parameter references
- CloudFormation dynamic references
- CodeBuild environment variables
- App Runner environment variables
- ECS secret values
A direct SDK or AWS CLI GetParameter call can still work when an integration does not. Do not assume a service feature that accepts a local parameter name also accepts a cross-account parameter ARN.
Option 2: share a Secrets Manager secret
Secrets Manager does not use RAM for this design. Authorization is expressed directly in a secret resource policy, plus the consumer identity policy and KMS key policy.
Create the secret with a customer-managed key
set +x
read -r -s -p "Synthetic test token: " REGISTRATION_TOKEN
printf '\n'
export SECRET_ARN=$(
aws secretsmanager create-secret \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--name "${SECRET_NAME}" \
--description "Security agent bootstrap token" \
--kms-key-id "${PRIMARY_KEY_ARN}" \
--secret-string "${REGISTRATION_TOKEN}" \
--tags \
Key=Purpose,Value=SecurityAgentBootstrap \
Key=SecurityDomain,Value=USNonProduction \
--query 'ARN' \
--output text
)
unset REGISTRATION_TOKEN
Capture the complete ARN returned by CreateSecret. Secrets Manager appends six characters to the name in the ARN. Partial ARNs are error-prone, particularly when a secret name itself ends with a hyphen followed by six characters.
Attach an OU-scoped resource policy
The following policy allows only principals that are:
- Members of the expected organization
- In the selected OU or one of its descendants
- Using a role named
SharedSecretReaderunder the expected role path
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowTargetOUWorkloadRoles",
"Effect": "Allow",
"Principal": "*",
"Action": [
"secretsmanager:DescribeSecret",
"secretsmanager:GetSecretValue"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-a1b2c3d4e5"
},
"ForAnyValue:StringLike": {
"aws:PrincipalOrgPaths": "o-a1b2c3d4e5/r-abcd/ou-abcd-11111111/ou-abcd-12345678/*"
},
"ArnLike": {
"aws:PrincipalArn": "arn:aws:iam::*:role/workload/SharedSecretReader"
}
}
}
]
}
aws:PrincipalOrgPaths is multivalued, which is why the policy uses a set operator. Include the complete organization path, not only the target OU ID. To share with the entire organization, remove the OU-path condition but retain aws:PrincipalOrgID and a workload-role restriction.
Save the policy as secret-resource-policy.json, validate it, and then attach it with public-policy blocking enabled:
aws secretsmanager validate-resource-policy \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--secret-id "${SECRET_ARN}" \
--resource-policy file://secret-resource-policy.json \
--query '{Passed:PolicyValidationPassed,Errors:ValidationErrors}' \
--output json
aws secretsmanager put-resource-policy \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--secret-id "${SECRET_ARN}" \
--resource-policy file://secret-resource-policy.json \
--block-public-policy
In my testing, policies constrained by either aws:PrincipalOrgID or aws:PrincipalOrgPaths passed BlockPublicPolicy validation and worked cross-account. An unrestricted Principal: "*" policy failed with BlockPublicPolicyCheck.
The wildcard principal is safe only because fixed organization, OU, and role conditions constrain it. Keep --block-public-policy in deployment and update workflows; do not treat one successful validation as permanent approval for future policy changes.
Retrieve the shared secret
Use the complete owner-account ARN:
aws secretsmanager get-secret-value \
--profile "${CONSUMER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--secret-id "${SECRET_ARN}" \
--version-stage AWSCURRENT \
--query 'SecretString' \
--output text
A short name makes Secrets Manager search the consumer account and returns ResourceNotFoundException. Shared secrets also do not appear in the consumer’s ListSecrets results. Maintain an approved ARN catalog or inject the ARN as nonsecret deployment metadata.
Unlike Parameter Store, GetSecretValue has no return-ciphertext mode. Secrets Manager performs the KMS operation before returning SecretString or SecretBinary.
If the secret uses aws/secretsmanager, cross-account retrieval fails even when the secret resource policy allows the caller. The service returns an explicit error that the default KMS service key cannot be used for a secret accessed from another account.
Replicate the secret to another Region
Create a customer-managed KMS key in us-west-2, apply an equivalent regional key policy, and capture its ARN as REPLICA_KEY_ARN. Then ask Secrets Manager to create a read-only replica:
aws secretsmanager replicate-secret-to-regions \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--secret-id "${SECRET_ARN}" \
--add-replica-regions \
"Region=${REPLICA_REGION},KmsKeyId=${REPLICA_KEY_ARN}" \
--query 'ReplicationStatus[].{Region:Region,Status:Status,KmsKeyId:KmsKeyId,Message:StatusMessage}' \
--output table
Poll the primary until the replica reports InSync:
aws secretsmanager describe-secret \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--secret-id "${SECRET_ARN}" \
--query 'ReplicationStatus[].{Region:Region,Status:Status,Message:StatusMessage}' \
--output table
The replica ARN has the same account, name, and six-character suffix; only the Region changes:
export REPLICA_SECRET_ARN="arn:aws:secretsmanager:${REPLICA_REGION}:${SECRET_OWNER_ACCOUNT_ID}:secret:org/bootstrap/security-agent/registration-token-AbCdEf"
Secrets Manager copies the secret value, versions, tags, and resource policy. It does not copy or synchronize the destination KMS key policy. The consumer role also needs IAM permissions for the replica secret ARN and replica KMS key ARN.
Read through the local endpoint:
aws secretsmanager get-secret-value \
--profile "${CONSUMER_PROFILE}" \
--region "${REPLICA_REGION}" \
--secret-id "${REPLICA_SECRET_ARN}" \
--version-stage AWSCURRENT \
--query 'SecretString' \
--output text
Updates and rotation occur in the primary Region and propagate to replicas. A direct write to a replica fails with an operation-not-permitted error. If regional failover requires writes, promote the replica to an independent secret from the replica Region:
aws secretsmanager stop-replication-to-replica \
--profile "${OWNER_PROFILE}" \
--region "${REPLICA_REGION}" \
--secret-id "${REPLICA_SECRET_ARN}"
Promotion changes the operating model. Define failback, conflict handling, rotation ownership, and resource-policy management before an incident.
Native replication is same-account only. The API’s replica structure accepts Region and KmsKeyId; it has no destination-account field. Cross-account copies require custom automation and become independent secrets with independent versions, rotation state, ARNs, policies, and billing.
It is also possible to call the primary Region from workloads in another Region without creating a replica. That reduces stored copies but creates a cross-Region runtime dependency. Use replicas for regional independence, not merely to reduce milliseconds of latency.

KMS multi-Region keys do not make either service global
A KMS multi-Region key consists of a primary key and one or more regional replica keys with the same mrk- key ID and cryptographic material. Ciphertext encrypted directly under one member can be decrypted by another member in a different Region.
Create and replicate an MRK with the CLI:
export MRK_PRIMARY_ARN=$(
aws kms create-key \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--multi-region \
--description "Shared bootstrap MRK primary" \
--key-usage ENCRYPT_DECRYPT \
--key-spec SYMMETRIC_DEFAULT \
--query 'KeyMetadata.Arn' \
--output text
)
aws kms replicate-key \
--profile "${OWNER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--key-id "${MRK_PRIMARY_ARN}" \
--replica-region "${REPLICA_REGION}" \
--query 'ReplicaKeyMetadata.{Arn:Arn,State:KeyState,Type:MultiRegionConfiguration.MultiRegionKeyType}' \
--output table
However, every member is an independent regional KMS resource with its own:
- Key ARN and policy
- Aliases and grants
- Description and tags
- Enabled/disabled state
- Deletion lifecycle
- Monthly key charge
Policies and tags do not synchronize after replication. In my testing, the primary description contained a marker while a replica created without --description had an empty description.
For Parameter Store and Secrets Manager, MRKs do not remove the need for service-level replication. These services treat each member as a regional key and encrypt the regional resource under the regional key ARN. Use MRKs when portable ciphertext is an explicit requirement or when a common key ID provides operational value—not as a substitute for replicating the parameter or secret.
Deletion has another lifecycle trap. A scheduled replica enters PendingDeletion with a date. A primary with existing replicas enters PendingReplicaDeletion and has no deletion date; its waiting period begins only after every replica is deleted. Inventory all members before scheduling deletion.
Empirical test results
My testing used synthetic values in one owner sandbox account and one consumer sandbox account in the same organization. Resources were created in us-east-1 and us-west-2, exercised through separate AWS CLI profiles, and then deleted. Propagation intervals below are observations, not service-level commitments.
| Test | Observed result | Architectural implication |
|---|---|---|
| Associate a Standard parameter with RAM | Resource association FAILED |
Sharing requires Advanced tier |
Share Advanced SecureString using aws/ssm |
Resource association FAILED |
A customer-managed key is a sharing prerequisite, not an optional hardening step |
| Retrieve shared parameter by short name | ParameterNotFound |
Consumers must store/use the owner ARN |
| Retrieve encrypted parameter before KMS grant, without decryption | Encrypted envelope returned | SSM and KMS authorization are separate |
| Retrieve the same parameter with decryption before KMS grant | InvalidKeyId |
RAM permission alone does not expose plaintext |
Call us-west-2 SSM with a us-east-1 ARN |
ValidationException: Incorrect region |
Endpoint Region must match ARN Region |
Call GetParameterHistory through default RAM permission |
AccessDeniedException |
History is a separate sharing decision |
Call GetParametersByPath with a shared ARN path |
Validation failure; action absent from RAM permissions | Do not design shared hierarchical enumeration |
| Read an implicit share before promotion | Direct ARN read succeeded; shared inventory was empty | Access and discoverability differ |
Promote an implicit policy missing DescribeParameters |
UnmatchedPolicyPermissionException |
Promotion requires a standard managed-permission match |
| Share to an account, OU, and organization | All associated; no in-organization invitations | RAM tracks Organizations membership |
| Update east SSM parameter | East became version 3; west remained version 1 | Parameter Store has no native synchronization |
| Read a secret before attaching a resource policy | AccessDeniedException |
Consumer IAM and KMS policies are insufficient by themselves |
Read cross-account secret using aws/secretsmanager |
Explicit default-key cross-account error | Customer-managed KMS key is mandatory |
| Retrieve shared secret by short name | ResourceNotFoundException |
Use the complete owner ARN |
| Validate org- and OU-constrained wildcard principals | Validation passed; live reads succeeded | PrincipalOrgID/PrincipalOrgPaths can safely scale policy scope when combined with other restrictions |
| Validate unrestricted wildcard principal | BlockPublicPolicyCheck failed |
Keep policy validation enabled |
| Replicate secret to second Region | Status reached InSync; tags, policy, and version ID matched |
Native replication includes value and selected metadata |
| Write to replica | Operation not permitted; call primary Region | Replicas are read-only until promoted |
| Update primary secret | Same new version ID appeared in replica within the five-second test interval | Replication is asynchronous; do not treat the observed interval as an SLA |
Supply AccountId to secret replication |
Client validation rejected the field | Native replication cannot target another account |
| Remove RAM share | Consumer read was denied within the four-second test interval | Resource-side revocation is fast, but application caches can retain plaintext |
| Remove primary secret policy | Reads failed in both Regions after policy propagation | Replica resource policy follows the primary |
| Inspect CloudTrail | Reads appeared in consumer; cross-account KMS decrypts appeared in caller and key-owner accounts | Aggregate audit data from both sides |
| Schedule MRK deletion | Replica: PendingDeletion; primary: PendingReplicaDeletion |
Delete/schedule replicas before expecting the primary countdown to begin |
Architecture patterns and tradeoffs
Pattern A: central owner account with one local copy per Region
A security or shared-services account owns the parameter or secret. Workload accounts read it through OU-scoped authorization. Every active workload Region contains a regional resource and regional KMS key.
- Secrets Manager: native replicas keep values, versions, tags, and resource policies synchronized.
- Parameter Store: custom event-driven replication plus periodic reconciliation is required.
This is usually the best balance of central governance and regional availability. It avoids one copy per account while keeping runtime traffic in-Region.
Pattern B: central owner account with cross-Region reads
Only one regional copy exists. All workloads explicitly call that Region.
Advantages:
- Fewer stored copies and KMS keys
- One authoritative resource
- No replication conflict
Disadvantages:
- The primary Region is on every startup path
- Cross-Region latency and transfer apply
- Regional isolation and data-residency requirements may prohibit it
- A VPC interface endpoint normally connects to its regional AWS service; cross-Region private connectivity requires additional network design
Use this only when startup can tolerate the dependency or has a controlled fallback.
Pattern C: independent copy in every workload account and Region
Each account owns its secret, policy, and KMS key. A central system distributes updates.
Advantages:
- Strong account isolation
- No cross-account runtime dependency
- Local service integrations generally work without shared-resource restrictions
Disadvantages:
- Copy count grows as accounts × Regions × security domains
- Rotation and revocation become distributed transactions
- Drift is inevitable without reconciliation
- Storage, KMS, endpoint, and operational costs increase
Choose this when account autonomy and containment are more important than centralized lifecycle simplicity.
Pattern D: assume a role or call a credential broker
A workload assumes a narrowly scoped role in the owner account, or presents its AWS identity to a broker that returns a short-lived registration credential.
This avoids a resource policy on every value and can centralize contextual decisions, but it adds STS or broker availability, trust policies, session controls, and another audited service path. A broker is often the strongest design when the external control plane can mint single-use credentials.
Pattern E: one token per security domain
When the control plane organizes agents into sites or environments, align tokens with those boundaries. For example:
- US production token → production OU paths only
- US non-production token → non-production and sandbox OU paths only
- International token → international OU paths only
Store each as a separate parameter or secret. Give each an independent resource policy, rotation runbook, and alerting context. A dedicated KMS key per domain gives the strongest cryptographic boundary; one tightly conditioned key per Region costs less and can still restrict each resource prefix through encryption context.
Private network access
Resource policies make access private in the authorization sense; they do not force packets to remain off public AWS service endpoints. Workloads without NAT or internet egress can use interface VPC endpoints with private DNS.
For Parameter Store retrieval, create an endpoint for the regional SSM service:
aws ec2 create-vpc-endpoint \
--profile "${CONSUMER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--vpc-id vpc-0123456789abcdef0 \
--vpc-endpoint-type Interface \
--service-name "com.amazonaws.${PRIMARY_REGION}.ssm" \
--subnet-ids \
subnet-11111111111111111 \
subnet-22222222222222222 \
subnet-33333333333333333 \
--security-group-ids sg-0123456789abcdef0 \
--private-dns-enabled
For Secrets Manager:
aws ec2 create-vpc-endpoint \
--profile "${CONSUMER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--vpc-id vpc-0123456789abcdef0 \
--vpc-endpoint-type Interface \
--service-name "com.amazonaws.${PRIMARY_REGION}.secretsmanager" \
--subnet-ids \
subnet-11111111111111111 \
subnet-22222222222222222 \
subnet-33333333333333333 \
--security-group-ids sg-0123456789abcdef0 \
--private-dns-enabled
Allow inbound TCP 443 to the endpoint ENIs only from approved workload security groups. Restrict the endpoint policy as another defense layer, but do not use it as a replacement for identity, resource, or KMS policies.
The workload does not need a KMS VPC endpoint for normal GetParameter --with-decryption or GetSecretValue operations. Parameter Store or Secrets Manager calls KMS on the principal’s behalf. A KMS endpoint is needed only when the workload makes direct KMS API calls.
Provision local endpoints in every Region used at runtime. PrivateLink endpoint-hour charges can exceed the storage cost of a small number of secrets, so include network architecture in the service comparison.
Golden AMI bootstrap design
The AMI should contain:
- The agent binary and nonsecret configuration
- A trusted first-boot service
- A nonsecret site identifier or full regional parameter/secret ARN
- No registration token, decrypted cache, or token-bearing user data
At launch:
- The instance obtains temporary role credentials through IMDSv2.
- Deployment metadata maps the account/environment/site to a regional resource ARN.
- The first-boot service retrieves the value from the local regional endpoint.
- The service supplies the token to the agent through standard input or another mechanism that does not expose it in process arguments or logs.
- The agent exchanges the bootstrap token for its normal registered identity, when supported.
- The bootstrap process clears in-memory variables and does not persist plaintext to the AMI, EBS volume, console output, or shell trace.

Enforce IMDSv2 and restrict instance metadata access from untrusted containers or processes. Never place the secret in EC2 user data: user data is deployment metadata, not a secret store.
If the agent retrieves the token only once, avoid a long-lived local cache. If a workload reads a credential repeatedly, use a bounded client-side cache with a TTL shorter than the required revocation or rotation objective. Cache behavior is part of the security model: deleting a RAM share or resource policy cannot erase plaintext already held by a process.
Rotation and consistency
Parameter Store
Parameter Store retains versions but does not rotate an external credential. A complete rotation workflow must:
- Create or activate the new value in the external control plane.
- Update the primary parameter.
- Replicate and verify every regional parameter.
- Allow consumers to converge within a defined overlap window.
- Revoke the old value externally.
- Confirm no consumer is reading an old parameter version or cache entry.
Granting GetParameterHistory can undermine step 5 if the old external credential remains valid. Parameter history is operational metadata, not a rotation system.
Secrets Manager
Secrets Manager can coordinate rotation for supported AWS services and can invoke a Lambda rotation function for custom credentials. Regional replicas follow rotation performed in the primary Region. The external system must still support a safe rotation protocol—typically create, set, test, and finish—or an overlap window.
A rarely rotating registration token does not automatically justify Parameter Store. Rotation frequency is only one dimension; native regional replication, value size, policy operations, and integration support may still favor Secrets Manager.
Quotas and throughput
The most relevant defaults are:
| Dimension | Parameter Store | Secrets Manager |
|---|---|---|
| Values per account and Region | 10,000 Standard and 100,000 Advanced | 500,000 secrets |
| Value size | 4 KB Standard; 8 KB Advanced | 65,536 bytes |
| Retained versions | 100 | 100 |
| Default read throughput | 40 TPS shared by GetParameter, GetParameters, and GetParametersByPath |
10,000 TPS for GetSecretValue; 100 TPS for BatchGetSecretValue |
| Resource-policy size | Service-specific Parameter Store/RAM constraints | 20,480 characters per secret resource policy |
Parameter Store higher-throughput mode raises individual read limits and incurs additional charges. Shared-parameter throughput is enforced at the consumer account level, so one consuming account does not consume another account’s Parameter Store read quota.
Secrets Manager similarly attributes cross-account request throttling to the account of the calling identity, not the account that owns the secret. This reduces centralized noisy-neighbor coupling, but every workload still needs retries with exponential backoff and jitter.
Avoid updating a Secrets Manager value more frequently than once every ten minutes for a sustained period. Each update creates a version, and versions younger than 24 hours are not removed even when the normal 100-version cleanup threshold is exceeded.
Audit and detection
CloudTrail records Parameter Store, Secrets Manager, RAM, and KMS API activity. Query recent event history during validation:
aws cloudtrail lookup-events \
--profile "${CONSUMER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--lookup-attributes \
AttributeKey=EventName,AttributeValue=GetParameter \
--max-results 50 \
--query 'Events[].{Time:EventTime,User:Username,EventId:EventId}' \
--output table
aws cloudtrail lookup-events \
--profile "${CONSUMER_PROFILE}" \
--region "${PRIMARY_REGION}" \
--lookup-attributes \
AttributeKey=EventName,AttributeValue=GetSecretValue \
--max-results 50 \
--query 'Events[].{Time:EventTime,User:Username,EventId:EventId}' \
--output table
For cross-account KMS operations, AWS records events in both the caller account and the key-owner account. Correlate them by time, key ARN, principal, encryption context, and request metadata. Use an organization trail or CloudTrail Lake for durable, centralized analysis; event history alone is not a retention strategy.
Alert on at least:
- Reads by unexpected role paths, accounts, Regions, user agents, or VPC endpoints
- Resource-policy and RAM-share changes
- KMS key-policy, grant, state, rotation, and deletion changes
- Secret replication failures or prolonged non-
InSyncstatus - Parameter replication drift
- Use of
AWSPREVIOUSor explicit old parameter versions - Account movement into an authorized OU
- Retrieval spikes inconsistent with instance-launch volume
Do not put plaintext values in resource names, tags, policy conditions, CLI descriptions, or API request fields that CloudTrail records.
Cost model
Public prices as of September 2026:
Direct service charges
| Item | Price |
|---|---|
| Standard Parameter Store parameter | No additional storage charge |
| Advanced Parameter Store parameter | USD 0.05 per parameter-month, prorated hourly |
| Advanced Parameter Store API interactions | USD 0.05 per 10,000 interactions |
| Secrets Manager secret | USD 0.40 per secret-month, prorated hourly |
| Secrets Manager API calls | USD 0.05 per 10,000 calls |
| Customer-managed KMS key | USD 1.00 per key-month, prorated hourly |
| Symmetric KMS requests | Typically USD 0.03 per 10,000 after the 20,000-request monthly free tier |
| AWS RAM | No additional charge |
Every Secrets Manager replica is billed as a separate secret. Every KMS key—including each member of a multi-Region key set—is billed as a separate key. The first and second automatic or on-demand KMS key rotations each add USD 1 per month; further rotations do not increase the monthly storage charge. Keys scheduled for deletion do not incur the key-storage charge during the waiting period.
Three tokens in two Regions
Assume three site-scoped registration tokens, two Regions, and one shared customer-managed KMS key per Region:
Parameter Store baseline
6 Advanced parameters × $0.05 = $0.30/month
2 regional KMS keys × $1.00 = $2.00/month
Baseline before requests and networking = $2.30/month
Secrets Manager baseline
6 primary/replica secrets × $0.40 = $2.40/month
2 regional KMS keys × $1.00 = $2.00/month
Baseline before requests and networking = $4.40/month
If policy requires one KMS key per site per Region, six keys cost USD 6 per month and dominate both totals. Conversely, a regional KMS key shared across hundreds of tightly related secrets amortizes its fixed cost.
At 10,000 instance launches per month with one retrieval per launch, either service adds approximately USD 0.05 in service API charges. At 7.2 million uncached reads per month, the service API charge is approximately USD 36, before KMS and networking. Retrieval frequency and cache strategy matter more than the storage-price difference at scale.
Costs that are easy to omit
- Interface VPC endpoints are billed per endpoint ENI-hour and per GB. At an illustrative
us-east-1rate of USD 0.01 per hour, one endpoint deployed across three Availability Zones is approximately USD 21.90 per 730-hour month before data processing—more than the storage in the preceding example. - Custom Parameter Store replication incurs Lambda, EventBridge, logging, and operational costs.
- Custom Secrets Manager rotation incurs Lambda charges unless managed rotation applies.
- Cross-Region calls can incur data-transfer charges.
- Additional CloudTrail copies, CloudTrail Lake ingestion, S3 storage, KMS encryption, and alarms can add charges.
- Copies per account multiply secret/parameter and KMS-key inventory.
Cost is therefore an architecture property, not merely the advertised per-secret price.
Failure and revocation runbook
Document and test these cases before production:
Compromised consumer role
- Deny or disable the role in the consumer account.
- Remove the account/OU from the RAM share or secret policy if broader containment is required.
- Revoke the credential in the external control plane.
- Rotate the stored value and every regional copy.
- Investigate CloudTrail in both consumer and owner accounts.
Removing read access does not invalidate plaintext already retrieved. External revocation is mandatory for a bearer token.
Account moves between OUs
RAM OU shares and aws:PrincipalOrgPaths conditions follow Organizations membership. Treat MoveAccount as a privileged access-control operation. Alert on it, and test both access grant and access removal after moves.
Primary Region failure
- Parameter Store: select a predesignated regional parameter, verify reconciliation state, and prevent conflicting writes during failover.
- Secrets Manager: read the local replica. Promote it only if writes or rotation are required, and follow a defined failback process.
Owner-account closure or suspension
Centralized access depends on the owner account and its KMS keys. Parameter Store consumers lose access when the owner account closes; AWS documents recovery if the account is reopened during the post-closure period. Protect the owner account with appropriate governance and break-glass procedures.
KMS key disabled or scheduled for deletion
Monitor KMS key state in every Region. A disabled key breaks plaintext retrieval even when service policies remain correct. Multi-Region primaries remain in PendingReplicaDeletion until all replicas are gone, so deletion automation must understand the complete key set.
A production decision framework
Use the following sequence:
- Can AWS identity or a broker replace the shared bearer token? Use that design.
- Can the token be segmented by account, environment, or site? Segment it before selecting storage.
- Is native regional replication or coordinated rotation required? Prefer Secrets Manager.
- Is the value static, no larger than 8 KB, and supported by direct retrieval or the documented shared-parameter integrations? Parameter Store Advanced can be appropriate.
- Can workloads depend on another Region at runtime? If not, create local regional copies.
- Is account-level containment more important than centralized lifecycle? Consider copies per account despite the operational cost.
- Have identity, resource, KMS, endpoint, SCP, audit, caching, and revocation controls all been tested together? Do not approve the design based on policy inspection alone.

Conclusion
SSM Parameter Store and Secrets Manager can both distribute a protected value across an AWS organization, but they solve the surrounding lifecycle differently.
Parameter Store sharing is a RAM feature available only to Advanced parameters. It is cost-effective for relatively static values, but consumers must use full ARNs, integration support is limited, history is a separate permission, and multi-Region synchronization is entirely the platform team’s responsibility. The implicit resource-policy path adds a promotion and discoverability lifecycle that explicit RAM shares avoid.
Secrets Manager uses secret resource policies rather than RAM. It costs more per stored value, but provides native same-account regional replicas, coordinated version propagation, and rotation capabilities. It still requires a customer-managed KMS key and independent KMS policy in every Region, and native replication cannot copy a secret into another account.
For organization-scale bootstrap credentials, the strongest practical design is usually a dedicated owner account, separate credentials for each security domain, local regional resources, OU- and role-scoped access, tightly conditioned regional KMS keys, private endpoints, and centralized audit. Where possible, replace the shared token with an identity-based or short-lived registration flow. The safest organization-wide secret is the one that no longer needs to be organization-wide.
References
- Working with shared parameters in Parameter Store
- Choosing parameter tiers in Parameter Store
- AWS KMS encryption for Parameter Store SecureString parameters
- Systems Manager endpoints and quotas
- Systems Manager pricing
- Access Secrets Manager secrets from a different account
- Secrets Manager resource-based policies
- Replicate Secrets Manager secrets across Regions
- Secrets Manager quotas
- Secrets Manager pricing
- Allow users in other accounts to use a KMS key
- Create multi-Region replica KMS keys
- KMS pricing
- AWS PrivateLink pricing
