Repository: cloud-custodian/cloud-custodian

Issue:
c7n-org: define values that are inherited by policies
Our accounts are used by different teams therefore are associated with separate project codes, charge codes etc..

It would be extremely useful if we were able to define these in the c7n-org account configuration file and then inherited by the policies.

Here is an example concept:

**c7n-org configuration**
```yaml
accounts:
- account_id: '123123123123'
  name: account-1
  regions:
  - us-east-1
  - us-west-2
  role: arn:aws:iam::123123123123:role/CloudCustodian
  tags:
  - type:prod
  inherit:
  - project_code:W0023424
```

**policy example**
```yaml
policies:
- name: ec2-auto-tag-project-code
  resource: ec2
  description: |
    Tag any new instance with project code
  mode:
    type: cloudtrail
    role: arn:aws:iam::{account_id}:role/role
    events:
      - RunInstances
  filters:
    - tag:projectCode: {project_code}
  actions:
    - type: tag
      key: projectCode
      value: {project_code}
```


Discussion:
thanks for filing an issue, the feature sounds good to me.

Resolving patch:
diff --git a/c7n/policy.py b/c7n/policy.py
--- a/c7n/policy.py
+++ b/c7n/policy.py
@@ -831,13 +831,21 @@ def validate(self):
         for a in self.resource_manager.actions:
             a.validate()
 
-    def get_variables(self):
+    def get_variables(self, variables=None):
+        """Get runtime variables for policy interpolation.
+
+        Runtime variables are merged with the passed in variables
+        if any.
+        """
         # Global policy variable expansion, we have to carry forward on
         # various filter/action local vocabularies. Where possible defer
         # by using a format string.
         #
         # See https://github.com/capitalone/cloud-custodian/issues/2330
-        return {
+        if not variables:
+            variables = {}
+
+        variables.update({
             # standard runtime variables for interpolation
             'account': '{account}',
             'account_id': self.options.account_id,
@@ -861,7 +869,8 @@ def get_variables(self):
             'target_bucket_name': '{target_bucket_name}',
             'target_prefix': '{target_prefix}',
             'LoadBalancerName': '{LoadBalancerName}'
-        }
+        })
+        return variables
 
     def expand_variables(self, variables):
         """Expand variables in policy data.
diff --git a/tools/c7n_org/c7n_org/cli.py b/tools/c7n_org/c7n_org/cli.py
--- a/tools/c7n_org/c7n_org/cli.py
+++ b/tools/c7n_org/c7n_org/cli.py
@@ -78,6 +78,7 @@
                     {'type': 'array', 'items': {'type': 'string'}},
                     {'type': 'string', 'minLength': 3}]},
                 'external_id': {'type': 'string'},
+                'vars': {'type': 'object'},
             }
         },
         'subscription': {
@@ -88,6 +89,7 @@
                 'subscription_id': {'type': 'string'},
                 'tags': {'type': 'array', 'items': {'type': 'string'}},
                 'name': {'type': 'string'},
+                'vars': {'type': 'object'},
             }
         },
         'project': {
@@ -98,6 +100,7 @@
                 'project_id': {'type': 'string'},
                 'tags': {'type': 'array', 'items': {'type': 'string'}},
                 'name': {'type': 'string'},
+                'vars': {'type': 'object'},
             }
         },
     },
@@ -504,7 +507,7 @@ def run_account(account, region, policies_config, output_path,
         for p in policies:
 
             # Variable expansion and non schema validation (not optional)
-            p.expand_variables(p.get_variables())
+            p.expand_variables(p.get_variables(account.get('vars', {})))
             p.validate()
 
             log.debug(


Test patch:
diff --git a/tests/test_policy.py b/tests/test_policy.py
--- a/tests/test_policy.py
+++ b/tests/test_policy.py
@@ -311,6 +311,17 @@ def test_policy_region_expand_global(self):
 
 class TestPolicy(BaseTest):
 
+    def test_policy_variable_precedent(self):
+        p = self.load_policy({
+            'name': 'compute',
+            'resource': 'aws.ec2'},
+            config={'account_id': '00100100'})
+
+        v = p.get_variables({'account_id': 'foobar',
+                             'charge_code': 'oink'})
+        self.assertEqual(v['account_id'], '00100100')
+        self.assertEqual(v['charge_code'], 'oink')
+
     def test_policy_variable_interpolation(self):
 
         p = self.load_policy({