AWS Declarative Policies Explained: A New Way to Lock Down Account Settings
Service control policies deny API calls. Resource control policies set the outer permission boundary on resources. Neither one answers a question security teams have been asking for years: "How do I ensure that a given service is configured a specific way across every account in my organization, and have that hold even as the service evolves?" Declarative policies answer that question directly. Rather than restricting who can call an API, they enforce what state a service will be in, and they hold that state forward regardless of new APIs, new principals, or new accounts joining the organization.
Key Takeaways
- AWS declarative policies enforce service-level configuration states at the control plane, rather than the IAM authorization layer. The configuration holds regardless of which principal or API path attempts to change it, including service-linked roles.
- The most common conceptual error is treating declarative policies as a substitute for SCPs. The two mechanisms answer different questions: SCPs govern who can call which APIs, while declarative policies govern what state a service will be in regardless of how it's called.
- Declarative policies are durable by design. When a service adds a new API or feature, the enforced configuration remains in effect without requiring a policy update.
- The account status report is the readiness step most teams skip. Run it before attaching a policy to understand how far the current environment is from the intended baseline, instead of after enforcement is already live.
What AWS Declarative Policies Are
An AWS Declarative Policy is a management policy type within AWS Organizations that enforces a desired configuration state for specific AWS services across an organization, organizational unit (OU), or individual account. Where an SCP controls what API calls a principal can make, a declarative policy controls what state a service will be in. That distinction matters because the two mechanisms operate at different layers of the AWS stack.
Declarative policies are enforced in the service's control plane, rather than in the IAM authorization flow. A principal's permissions don't change how the policy applies. When a declarative policy sets VPC Block Public Access to block_bidirectional on an OU, that configuration holds for every account in that OU, regardless of whether the change is attempted by an IAM role, a user, or an AWS service acting through a service-linked role. Service-linked roles matter here specifically: SCPs and RCPs don't govern them, but declarative policies do.
AWS announced the general availability of declarative policies in December 2024, initially covering EC2, EBS, and VPC configurations. Since then, AWS has expanded the supported service list significantly, with S3 Block Public Access enforcement, Amazon Bedrock guardrail configuration, Amazon Inspector organization-level management, and AWS Shield Network Security Director all added through 2025.
Where Declarative Policies Sit in the AWS Policy Hierarchy
Using declarative policies requires AWS Organizations to be enabled for your account. Policies can only be created and managed from the organization's management account or from an account designated as a delegated administrator for the relevant service. For EC2 declarative policies specifically, you'll need trusted access enabled between EC2 and AWS Organizations before you can generate account status reports. The AWS Organizations console enables trusted access automatically when you create your first policy through the UI; CLI-based workflows require an explicit EnableAWSServiceAccess call with the ec2.amazonaws.com service principal.
Declarative policies are attached in the same places as other AWS Organizations management policies: the organization root, an OU, or an individual account. A policy attached to the root applies to every account in the organization. A policy attached to an OU applies to every account in that OU and its descendants. Accounts that join an organization automatically inherit any declarative policies in effect at the level they join.
The effective policy for a given account is the result of merging all declarative policies inherited from the hierarchy, plus any directly attached to the account itself. AWS uses inheritance operators to control how parent and child policies merge. The three operators available are:
@@assign replaces any inherited value with the specified value. For single-valued settings, it overwrites the parent. For multi-valued settings (JSON arrays), it removes all inherited values and replaces them with the specified set.
@@append adds specified values to the inherited set without removing existing values. This operator applies only to multi-valued settings.
@@remove removes specific inherited values from the effective policy without affecting other values. This operator also applies only to multi-valued settings.
In practice, @@assign is what you'll use for the vast majority of declarative policy work. AWS's Organizations console only exposes @@assign in its visual editor; @@append and @@remove are advanced features that require manual JSON authoring. They become relevant when you want a child OU policy to add to or subtract from an inherited set without replacing it entirely, such as expanding an approved AMI provider list at the OU level while keeping the root-level defaults in place. For most enforcement use cases, @@assign at the appropriate level in the hierarchy is the right tool.
Parent policies can restrict which operators child policies are permitted to use by including @@operators_allowed_for_child_policies in the policy document. Setting this to @@none prevents child policies from modifying the inherited value at all, which is how an organization root policy can lock a setting that no OU or account administrator can override.
When a declarative policy is detached, the service rolls back the enforced attribute to the state it was in before the policy was attached.
How Declarative Policies Differ from SCPs and RCPs
The table below captures the most operationally relevant distinctions. Understanding where each policy type governs helps you avoid the common mistake of trying to use one as a workaround for the other's limits.
| Policy Type | What It Governs | How It Governs | Governs Service-Linked Roles | Survives New APIs/Features |
|---|---|---|---|---|
| SCP | Maximum permissions for principals in member accounts | Controls which API calls are allowed at the API layer | No | No, new APIs need explicit coverage |
| RCP | Maximum permissions for resources in member accounts | Controls access to resources at the API layer | No | No, new APIs need explicit coverage |
| Declarative Policy | Configuration state of supported AWS services | Enforced at the service control plane, not the API | Yes | Yes, configuration persists as services evolve |
The durability distinction matters most. An SCP that denies ec2:DisableSerialConsoleAccess can be worked around if AWS introduces a new API that achieves the same effect, because the new API won't be in the SCP's deny list. A declarative policy that sets serial console access to disabled doesn't care how many APIs exist that could change that setting. The configuration is enforced at the service level, rather than by enumerating the API calls that could affect it.
For a deeper comparison of how SCPs and RCPs interact with each other and with the rest of the AWS policy evaluation chain, see AWS RCP vs. SCP.
Supported Services and Attributes
AWS has expanded declarative policy coverage at a steady pace since the December 2024 launch. The services and attributes below reflect the current state as of August 2026. The supported service list continues to grow, so the AWS Organizations documentation is the right place to check for the latest additions.
EC2 Policies (ec2_attributes)
EC2 policies cover the broadest set of attributes, all nested under the ec2_attributes key in the policy JSON.
| Attribute | What It Controls |
|---|---|
| vpc_block_public_access | Whether resources in VPCs and subnets can reach the internet through internet gateways. Modes: off, block_ingress, block_bidirectional |
| serial_console_access | Whether the EC2 serial console is accessible. Values: enabled, disabled |
| image_block_public_access | Whether AMIs can be publicly shared. Values: unblocked, block_new_sharing |
| allowed_images_settings | Which AMIs can be discovered and launched, scoped by provider account ID, image name pattern, marketplace product code, creation date, deprecation date, or image watermark. Supports up to 10 named criteria per policy. |
| instance_metadata_defaults | IMDS defaults for all new instance launches, including http_tokens (required enforces IMDSv2), http_put_response_hop_limit, http_endpoint, and instance_metadata_tags |
| snapshot_block_public_access | Whether EBS snapshots can be publicly shared. Values: unblocked, block_new_sharing, block_all_sharing |
| vpc_encryption_control | Whether VPC encryption controls are enabled and in which mode. Modes: unmanaged, attempt_monitor, attempt_enforce, with per-region resource type exclusions |
Additional Declarative Policy Types
The following services gained declarative policy support after the December 2024 launch and follow the same syntax and inheritance model as EC2 policies.
| Service | What the Declarative Policy Controls |
|---|---|
| Amazon S3 | Block Public Access configuration at the organization level (four BPA settings: BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets). Unlike other declarative policy types, a more permissive child policy can override a restrictive parent, so S3 BPA inheritance behaves differently from EC2. |
| Amazon Bedrock | Guardrail configuration enforcement across model inference calls for the organization |
| Amazon Inspector | Inspector scan enablement and configuration across organization accounts |
| AWS Shield NSDir | Network security director configuration across the organization |
Earlier Management Policy Types Using Declarative Syntax
AWS Organizations also includes an older set of management policy types that use the same declarative JSON syntax and inheritance operators, but predate the December 2024 declarative policies launch and are documented separately in the AWS Organizations console. They're included here because they're frequently confused with the newer declarative policy types and follow the same operational model.
| Service | What It Controls |
|---|---|
| AWS Backup | Backup plan enforcement across organization accounts. See AWS Tag and Backup Policies for a full breakdown. |
| Tag Policies | Tag key and value compliance enforcement across resource types. See AWS Tag and Backup Policies for syntax and examples. |
| AI Services Opt-out | Opt-out from AWS AI services using your data for model improvements |
| Upgrade Rollout | Staging and sequencing of automatic AWS service upgrades across accounts |
Policy Syntax and Examples
Declarative policies are JSON documents. The top-level key is fixed per service type, for example ec2_attributes for EC2 policies. You set values using inheritance operators, and @@assign is the most commonly used.
The examples below are copy-pasteable starting points for the most commonly needed EC2 policy configurations. Each one includes the relevant context for what the policy does and what to watch for before deploying it to production.
Enforce IMDSv2 organization-wide
This policy requires IMDSv2 for all new EC2 instance launches and prevents enabling IMDSv1 on existing instances. Before applying this,use the CloudWatch metric MetadataNoToken to audit your environment for instances still making IMDSv1 calls.
{ "ec2_attributes": { "exception_message": { "@@assign": "IMDSv2 is required organization-wide. See our internal documentation at YOUR-INTERNAL-WIKI-URL for guidance." }, "instance_metadata_defaults": { "http_tokens": { "@@assign": "required" }, "http_put_response_hop_limit": { "@@assign": "2" }, "http_tokens_enforced": { "@@assign": "enabled" } } } }Setting http_tokens_enforced to enabled while http_tokens is set to required will cause launch failures for any instance explicitly configured for IMDSv1. Before deploying this policy, use the CloudWatch MetadataNoToken metric to identify any instances still making IMDSv1 calls and remediate those first.
Block VPC public access, ingress only, with exclusions permitted
This policy blocks inbound internet traffic through internet gateways across all accounts in scope while allowing accounts to create VPC BPA exclusions for subnets or VPCs that legitimately need egress. block_ingress allows outbound traffic through NAT gateways and egress-only internet gateways.
{ "ec2_attributes": { "vpc_block_public_access": { "internet_gateway_block": { "mode": { "@@assign": "block_ingress" }, "exclusions_allowed": { "@@assign": "enabled" } } } } }Restrict AMI usage to approved providers and recent Amazon-published images
This policy enforces Allowed Images Settings, permitting only images from two approved internal account IDs and Amazon-published images that haven't been deprecated.
{ "ec2_attributes": { "allowed_images_settings": { "state": { "@@assign": "enabled" }, "image_criteria": { "criteria_1": { "allowed_image_providers": { "@@assign": [ "123456789012", "123456789013" ] } }, "criteria_2": { "allowed_image_providers": { "@@assign": [ "amazon" ] }, "deprecation_time_condition": { "maximum_days_since_deprecated": { "@@assign": 0 } } } } } } }Use audit_mode first when the service supports it, for example by setting "state": "audit_mode" for allowed_images_settings before moving to "enabled". Audit mode identifies noncompliant images without blocking their use, giving you a window to remediate before enforcement.
Lock EBS snapshot sharing across the organization
{ "ec2_attributes": { "snapshot_block_public_access": { "state": { "@@assign": "block_all_sharing" } } } }block_all_sharing makes previously public snapshots private immediately. block_new_sharing prevents new public sharing but leaves existing public snapshots accessible. Confirm which behavior your environment requires before selecting the mode.
Operational Commands
These two commands are the core of day-to-day declarative policy operations. Run both before and after any policy change to confirm the hierarchy is resolving as intended.
Viewing the effective policy for an account:
aws organizations describe-effective-policy
--policy-type DECLARATIVE_POLICY_EC2
--target-id TARGET_ACCOUNT_OR_OU_IDThis returns the merged effective policy for a given account or OU, not just the policy you directly attached. Run it before attaching to understand what's already inherited, and after attaching to confirm the merge resolved as expected.
Generating the account status report:
aws ec2 start-declarative-policies-report
--target-id TARGET_OU_OR_ORG_ID
--s3-bucket s3://YOUR-REPORT-BUCKET/prefix/The report must be written to an S3 bucket in the same region as the request. Trusted access must be enabled for EC2 in AWS Organizations before the report can run; the console enables this automatically, but CLI workflows require an explicit EnableAWSServiceAccess call with the ec2.amazonaws.com service principal. You can initiate the report from the management account or a delegated administrator account.
Common Mistakes
Expecting declarative policies to behave like SCPs for configuration enforcement. The instinct for many teams is to write an SCP that denies the relevant configuration-change API calls. That works until AWS introduces a new API that achieves the same change, at which point the SCP has a gap and the configuration can be altered. Declarative policies close that gap structurally by enforcing the state rather than the set of APIs that could affect it.
Not running the account status report before attaching. A policy that sets instance_metadata_defaults to require IMDSv2 will cause launch failures for any instance in scope that's explicitly configured for IMDSv1. The account status report shows exactly where the current environment stands on every attribute before any enforcement change touches production. Skipping the report means discovering those conflicts after the policy is live.
Confusing block_new_sharing with block_all_sharing for snapshots. block_new_sharing prevents new public sharing but leaves existing public snapshots visible. If the goal is to remove all public snapshot exposure, block_all_sharing is the correct value, and it takes effect immediately on already-public snapshots. The mode names are easy to conflate, and the difference in blast radius is significant.
Setting http_tokens_enforced to enabled before confirming http_tokens. Enabling IMDSv2 enforcement (http_tokens_enforced: enabled) while the http_tokens value is optional or no_preference will cause launch failures for any instance explicitly configured to allow IMDSv1. The http_tokens field and the http_tokens_enforced field interact, and AWS's documentation includes a specific warning about this combination. Audit the environment for instances making IMDSv1 calls using the CloudWatch MetadataNoToken metric before changing either field.
Assuming the effective policy is what you attached. When multiple policies exist across the hierarchy, the effective policy is the result of merging them using inheritance operators. An @@assign at the OU level can override what you set at the root. Run describe-effective-policy at the target account before and after attaching policies to confirm the merge is resolving as intended.
Forgetting that VPC BPA exclusions are managed separately. The declarative policy can set exclusions_allowed to enabled or disabled, but it can't create the exclusions themselves. The account that owns the VPC creates the exclusions. If your policy allows exclusions but the teams running those accounts don't know to create them, you may inadvertently block legitimate traffic flows without a clear remediation path.
Not including a custom error message. When a declarative policy blocks an action, the default error message isn't specific about why the action failed or what to do next. The exception_message field under ec2_attributes lets you include a plain-language explanation and a link to an internal wiki or ticketing system. That message appears in the error response and in CloudTrail, and it significantly reduces the number of support tickets generated when enforcement first lands in an account.
Best Practices
Use the account status report to stage rollouts, not just to check readiness. The report shows you the current configuration of every attribute across every in-scope account, which means you can identify which accounts are already compliant, which need remediation before enforcement, and which have configurations that will conflict with the policy outright. That breakdown is the input for a phased rollout: enforce first on compliant accounts, remediate conflicts in parallel, and expand scope once the pattern is established rather than attaching at the root and discovering conflicts under production load.
Use audit_mode for attributes that support it before moving to enforce. The allowed_images_settings attribute supports an audit_mode state that identifies noncompliant images without blocking their launch. Start there, review the results, remediate or document exceptions, and then move to enabled. Make this pattern a standard part of any rollout where enforcement will affect running workloads.
Define custom error messages for every policy. Include a plain-language description of the constraint and a link to the relevant internal documentation or ticketing process. Developers seeing a generic Access Denied don't know whether the block is a bug or deliberate; a clear message tells them what happened and where to go. CloudTrail also surfaces the message, which helps when investigating why an operation failed.
Store declarative policies in source control alongside your IaC definitions. Policies managed only through the AWS console are invisible to change management processes and difficult to audit. Define the policy JSON in Terraform or CloudFormation, treat the console as a read-only view, and apply the same change controls you'd apply to a firewall rule or an SCP.
Verify the effective policy at the target scope before attaching. Use describe-effective-policy to see what would apply to an account or OU given the current policy hierarchy. Do this before and after attaching new policies to confirm the inheritance operators are merging as intended. This is especially important in organizations with complex OU structures where multiple declarative policies may be in effect at different levels.
Use the delegated administrator pattern for large organizations. The management account can delegate the ability to manage declarative policies and run account status reports to a designated security or governance account. This keeps the management account's blast radius smaller and allows the security team to operate without requiring management account access for day-to-day policy operations.
Why Native
Declarative policies give security and platform teams a durable enforcement mechanism for AWS service configuration, something that SCPs have never been able to provide cleanly. The gap that remains is connecting those policies to the architectural intent behind them and keeping that connection legible as the environment changes underneath it.
Declarative policies don't manage themselves. New accounts join the organization and inherit the effective policy, but whether it still reflects the architecture's intent depends on how carefully the hierarchy was designed when the policy was first written. OU structures get reorganized and the inheritance chain shifts. AWS ships a new attribute for an existing service, and the accounts that needed it most are the ones nobody thought to check. Teams create VPC BPA exclusions that the policy permits, but those exclusions accumulate without review and quietly become permanent gaps in a control that was supposed to be closed. Each of these changes is individually reasonable. Together they create the same drift problem that affects every other layer of cloud security: the policy says the right thing, but the environment no longer reflects what the policy intended.
Native's Organization Intelligence maintains a live topology of every account, workload, identity, and resource across your environment, connected to a live map of what your providers are actually enforcing and where enforcement is absent. When a new account joins the organization, Native surfaces whether the effective declarative policy it inherited matches the architectural intent for that account's zone. When a VPC BPA exclusion gets created under a permissive policy, Exception Management tracks it with a documented justification and expiration date rather than letting it accumulate into a permanent gap. When AWS ships a new attribute for a service already under declarative policy coverage, Integrated Enforcement Feedback surfaces the gap so you can close it before the next audit cycle. That's the operating model described in The Architecture of Intent: zones, boundaries, and baselines enforced through the native controls each provider already ships, kept true as the environment keeps changing.
See how Native works across AWS, Azure, Google Cloud, and OCI.
FAQ
Can a declarative policy and an SCP both cover the same behavior?
Yes. They operate at different layers and don't conflict. An SCP can deny the ec2:ModifyVpcBlockPublicAccessOptions API call, and a declarative policy can independently enforce the VPC BPA configuration state. Both will apply. In practice, using a declarative policy for the configuration state is more durable than relying solely on an SCP, since the declarative policy covers new APIs automatically.
What happens if an account already has the enforced setting when the policy is attached?
Nothing changes. The policy enforces the state, and if the state already matches, there's no change and no disruption. The value of checking the account status report first is confirming this before attaching rather than hoping for it.
Do declarative policies appear in CloudTrail?
Yes. When a declarative policy blocks an action, CloudTrail records the failure with the policy context. This is how you trace enforcement activity at scale and investigate why specific operations failed.
Can a child OU policy override a stricter parent declarative policy?
It depends on what operators the parent policy allows. If the parent uses @@operators_allowed_for_child_policies: @@none, child policies can't modify the inherited value. If the parent doesn't restrict child operators, a child policy using @@assign can override the inherited value. Amazon S3 declarative policies are a notable exception: they allow a more permissive child policy to override a restrictive parent, unlike most other declarative policy types.
What happens to resources already in a noncompliant state when a policy is attached?
For most attributes, the policy enforces the state going forward and blocks changes that would maintain or worsen noncompliance, but doesn't forcibly remediate existing resources. The account status report shows the current state of every in-scope account, which is the tool for identifying how many accounts are starting from a noncompliant position. VPC encryption controls are an exception: when mode is set to attempt_enforce, the service actively attempts to move VPCs to enforce mode.
Can declarative policies be used with AWS Control Tower?
Yes. AWS Control Tower supports declarative policies as a preventive control type. Controls implemented through declarative policies in Control Tower appear in the Control Tower console alongside other control types. You can deploy and manage them through the Control Tower workflow in addition to direct Organizations management.
How do I scope a declarative policy to specific accounts in an OU without affecting the whole OU?
Declarative policies apply to the scope they're attached to. If you need to apply a policy to some accounts in an OU but not others, either move those accounts into a separate OU and attach the policy there, or attach it directly to individual accounts. There's no conditional filtering within the scope of a single declarative policy attachment.