Multi-Account AWS Security & Governance (Resource Policies / aws PrincipalOrgID) - Overview.
Scope:
- Intro,
- Key Benefits for Security & Governance,
- Implementation Patterns,
- Flavor 1: S3 Bucket Policy (Organization-Wide Access),
- Sample S3 Bucket Policy (Organization-Wide Access),
- Flavor 2: SCP Guardrail (Enforcing Organization Boundaries),
- Sample SCP Guardrail (Enforcing Organization Boundaries),
- Resources for Further Governance,
- The Concept of AWS Resource Policies (Deep Dive),
- Common Samples of AWS Services and Resource Policy Types,
- Sample resource policy usually & Tags,
- Benefits of Using aws:PrincipalOrgID,
- Gotchas and Edge Cases,
- Sample of S3 Bucket Policy that Restricts Access to Org,
- Sample Policy that combined S3 Bucket Restricts Access to Org with explicit Deny for public access,
- Testing and Validation Procedures,
- Real-World Pattern for Multi-Account Security,
- Comparison with Alternatives,
- Best Practices.
Intro:
- In multi-account AWS environments, the aws:PrincipalOrgID condition key is a foundational governance tool for securing shared resources.
- The aws:PrincipalOrgID condition key allows twtech to restrict access to resources such as:
- S3 buckets,
- KMS keys,
- Lambda functions—to only those principals (users or roles) that belong to twtech specific AWS Organization.
- Dynamic Membership: Permissions automatically apply to new accounts added to the organization, removing the need to manually update Resource-Based Policies with individual account IDs.
- Scalable Guardrails: It simplifies the management of 100s or 1,000s of accounts by using a single Organization ID (e.g., accountID) as the security boundary.
- Cross-Account Safety: It prevents accidental exposure to external accounts by ensuring that even if a wildcard (*) is used in the "Principal" element, the "Condition" block restricts access to twtech organization.
- Organization Enforcement: Central security teams can use Service Control Policies (SCPs) or Resource Control Policies (RCPs) to enforce the use of this condition across all accounts.
- This policy allows any principal from twtech AWS Organization to access objects in a specific bucket, provided they also have identity-based permissions in their own account.
- This Service Control Policy prevents any IAM principal within twtech organization from accessing resources that do not belong to its allowed organization, effectively creating a data perimeter.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "twtechEnforceDataPerimeter",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:ResourceOrgID": "accountID"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
}
}
}
]
}- Control Access Based on OU or Org: Deep dive into using aws:PrincipalOrgID and aws:ResourceOrgID together.
- AWS IAM Condition Keys: Full reference for all global condition keys.
- AWS Control Tower: Orchestrates Organizations and SCPs to set up a governed multi-account landing zone.
NB:
- This forms the base Resource Policies and aws:PrincipalOrgID global condition key.
1. The Concept of AWS
Resource Policies (Deep Dive)
- Resource policies are policies
attached directly to a resource,
rather than
to an IAM identity (like
a user or role).
- Resource policies define who (the principal) can access that resource and under what conditions.
Common Samples of AWS Services and Resource
Policy Types:
|
AWS Service |
Resource Policy
Type |
|
S3 |
Bucket policy |
|
KMS |
Key policy |
|
SQS |
Queue policy |
|
SNS |
Topic policy |
|
Secrets Manager |
Secret policy |
|
EventBridge |
Event bus policy |
|
ECR |
Repository policy |
|
Lambda |
Function resource policy |
# Sample resource policy usually & Tags
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::twtech-s3bucket/*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "twtechOrgID"
}
}
}
]
}
# NB:
- In this above example, even though the Principal is "*", the Condition ensures that only IAM identities within a specific AWS Organization (by Org ID) can access the resource.
2. Understanding aws:PrincipalOrgID
- aws:PrincipalOrgID is a global condition key that represents the Organization ID of the principal’s AWS account — i.e., which AWS Organization the principal (user/role) belongs to.
- twtech has its Org ID with:
- aws organizations describe-organization → returns something like "twtechOrgID"
- When a request is made to access a resource, AWS evaluates the organization of the principal’s account.
Use Case
- aws:PrincipalOrgID is primarily used to allow access from any account within your AWS Organization, while blocking everyone else.
NB:
- twtech have 30 AWS accounts managed under one AWS Organization.
- twtech want a shared S3 bucket that only those accounts can read/write to — not the public Internet.
- Instead of maintaining a list of 30 Account IDs, twtech can do:
"Condition":
{ "StringEquals": { "aws:PrincipalOrgID": "twtechOrgID"
} }
3. Benefits of Using aws:PrincipalOrgID
|
Benefit |
Description |
|
Simpler management |
Avoids enumerating individual
account IDs in policies. |
|
Automatic coverage |
New accounts added to your Organization
are automatically included. |
|
Defense-in-depth |
Protects even if someone sets "Principal": "*" or similar broad permissions. |
|
Supports
cross-account resource sharing. |
Enables secure, scalable access
across Org members. |
4. Gotchas and Edge Cases
1. Works Only if the Principal Is an AWS Account Member of an
Org
- If the principal’s account is not part of any Organization, the key won’t exist — and access will fail when the condition is enforced.
2. Doesn’t Work for Anonymous or Federated Identities
If the request comes from:
- A public/anonymous user (Principal:
"*")
- A web identity (Cognito, OIDC, etc.)
- A federated SAML user from outside AWS → aws:PrincipalOrgID is not present, and the condition evaluates to false.
3. Principal Evaluation Happens Early
- AWS checks the Principal and Conditions before IAM role assumption or Security Token Service (STS) federation.
- If the principal identity’s source account cannot be resolved to an Org ID, the condition fails.
4. aws:PrincipalOrgPaths Is More Granular
- There’s also a related key:
"aws:PrincipalOrgPaths":
["twtechOrgID/r-1234/twtechDevOu"]
NB:
- The above Tags allows scoping to specific OUs (Organizational Units) instead of the entire Org.
5. Sample of S3 Bucket Policy that Restricts Access to Org
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "twtechAllowAccessWithinOrg",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::twtech-org-shared-bucket",
"arn:aws:s3:::twtech-org-shared-bucket/*"
],
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID":
"twtechOrgID"
}
}
}
]
}
# Sample Policy that combined S3 Bucket Restricts Access to Org with explicit Deny for public access
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::twtech-org-shared-bucket/*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalOrgID": "twtechOrgID"
}
}
}
6. Testing and
Validation Procedures
NB:
- twtech can simulate this in IAM Policy Simulator or use AWS CLI:
aws
sts assume-role --role-arn arn:aws:iam<twtechACCOUNT_ID>:role/twtechRole
Then list the S3 access:
aws s3
ls s3://twtech-org-shared-bucket
NB:
- If twtech current account is in the org, it should succeed; otherwise, it should fail with:
An error occurred (AccessDenied)
7. Real-World Pattern for Multi-Account Security
NB:
- In multi-account
environments, twtech uses aws:PrincipalOrgID in:
- S3 buckets shared
for centralized logging
- KMS keys for encryption across Org accounts
- EventBridge buses for Org-wide event routing
- Secrets Manager for Org-only access
- ECR repositories shared with Dev/Prod accounts
8. Comparison with Alternatives
|
Approach |
Pros(advantages) |
Cons(Limitations) |
|
List account IDs manually |
Precise |
Hard to scale, error-prone |
|
Use aws:PrincipalOrgID |
Dynamic, clean |
Requires Org membership |
|
Use SCPs (Service Control Policies) |
Central governance |
Coarse-grained (Org-level) |
|
IAM trust policies per role |
Granular |
Tedious for shared resources |
9. Best Practices
- Always
combine aws:PrincipalOrgID with "Principal": "*" for flexible, Org-scoped access.
- Keep
twtech Organization ID secret —
don’t publish it publicly.
- Verify
new resources (S3, KMS,
EventBridge, etc.) have aws:PrincipalOrgID conditions to prevent unintended public access.
- Use Service Control Policies (SCPs) to deny access to resources without that condition, to enforcing compliance Org-wide.
No comments:
Post a Comment