Beispiel #1
0
def resource_vocabulary(cloud_name=None, qualify_name=True):
    vocabulary = {}
    resources = {}

    for cname, ctype in clouds.items():
        if cloud_name is not None and cloud_name != cname:
            continue
        for rname, rtype in ctype.resources.items():
            if qualify_name:
                resources['%s.%s' % (cname, rname)] = rtype
            else:
                resources[rname] = rtype

    for type_name, resource_type in resources.items():
        classes = {'actions': {}, 'filters': {}, 'resource': resource_type}
        actions = []
        for action_name, cls in resource_type.action_registry.items():
            actions.append(action_name)
            classes['actions'][action_name] = cls

        filters = []
        for filter_name, cls in resource_type.filter_registry.items():
            filters.append(filter_name)
            classes['filters'][filter_name] = cls

        vocabulary[type_name] = {
            'filters': sorted(filters),
            'actions': sorted(actions),
            'classes': classes,
        }

    vocabulary["mode"] = {}
    for mode_name, cls in execution.items():
        vocabulary["mode"][mode_name] = cls

    return vocabulary
Beispiel #2
0
def generate(resource_types=()):
    resource_defs = {}
    definitions = {
        'resources': resource_defs,
        'iam-statement': {
            'additionalProperties': False,
            'type': 'object',
            'properties': {
                'Sid': {'type': 'string'},
                'Effect': {'type': 'string', 'enum': ['Allow', 'Deny']},
                'Principal': {'anyOf': [
                    {'type': 'string'},
                    {'type': 'object'}, {'type': 'array'}]},
                'NotPrincipal': {'anyOf': [{'type': 'object'}, {'type': 'array'}]},
                'Action': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'NotAction': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'Resource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'NotResource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'Condition': {'type': 'object'}
            },
            'required': ['Sid', 'Effect'],
            'oneOf': [
                {'required': ['Principal', 'Action', 'Resource']},
                {'required': ['NotPrincipal', 'Action', 'Resource']},
                {'required': ['Principal', 'NotAction', 'Resource']},
                {'required': ['NotPrincipal', 'NotAction', 'Resource']},
                {'required': ['Principal', 'Action', 'NotResource']},
                {'required': ['NotPrincipal', 'Action', 'NotResource']},
                {'required': ['Principal', 'NotAction', 'NotResource']},
                {'required': ['NotPrincipal', 'NotAction', 'NotResource']}
            ]
        },
        'actions': {},
        'filters': {
            'value': ValueFilter.schema,
            'event': EventFilter.schema,
            'age': AgeFilter.schema,
            # Shortcut form of value filter as k=v
            'valuekv': {
                'type': 'object',
                'minProperties': 1,
                'maxProperties': 1},
        },
        'filters_common': {
            'comparison_operators': {
                'enum': list(OPERATORS.keys())},
            'value_types': {'enum': VALUE_TYPES},
            'value_from': ValuesFrom.schema,
            'value': {'oneOf': [
                {'type': 'array'},
                {'type': 'string'},
                {'type': 'boolean'},
                {'type': 'number'},
                {'type': 'null'}]},
        },
        'policy': {
            'type': 'object',
            'required': ['name', 'resource'],
            'additionalProperties': False,
            'properties': {
                'name': {
                    'type': 'string',
                    'pattern': "^[A-z][A-z0-9]*(-[A-z0-9]+)*$"},
                'region': {'type': 'string'},
                'tz': {'type': 'string'},
                'start': {'format': 'date-time'},
                'end': {'format': 'date-time'},
                'resource': {'type': 'string'},
                'max-resources': {'anyOf': [
                    {'type': 'integer', 'minimum': 1},
                    {'$ref': '#/definitions/max-resources-properties'}
                ]},
                'max-resources-percent': {'type': 'number', 'minimum': 0, 'maximum': 100},
                'comment': {'type': 'string'},
                'comments': {'type': 'string'},
                'description': {'type': 'string'},
                'tags': {'type': 'array', 'items': {'type': 'string'}},
                'mode': {'$ref': '#/definitions/policy-mode'},
                'source': {'enum': ['describe', 'config']},
                'actions': {
                    'type': 'array',
                },
                'filters': {
                    'type': 'array'
                },
                #
                # TODO: source queries should really move under
                # source. This was initially used for describe sources
                # to expose server side query mechanisms, however its
                # important to note it also prevents resource cache
                # utilization between policies that have different
                # queries.
                'query': {
                    'type': 'array', 'items': {'type': 'object'}}

            },
        },
        'policy-mode': {
            'anyOf': [e.schema for _, e in execution.items()],
        },
        'max-resources-properties': {
            'type': 'object',
            'properties': {
                'amount': {"type": 'integer', 'minimum': 1},
                'op': {'enum': ['or', 'and']},
                'percent': {'type': 'number', 'minimum': 0, 'maximum': 100}
            }
        }
    }

    resource_refs = []
    for cloud_name, cloud_type in clouds.items():
        for type_name, resource_type in cloud_type.resources.items():
            if resource_types and type_name not in resource_types:
                continue
            alias_name = None
            r_type_name = "%s.%s" % (cloud_name, type_name)
            if cloud_name == 'aws':
                alias_name = type_name
            resource_refs.append(
                process_resource(
                    r_type_name,
                    resource_type,
                    resource_defs,
                    alias_name,
                    definitions,
                    cloud_name
                ))

    schema = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        'id': 'http://schema.cloudcustodian.io/v0/custodian.json',
        'definitions': definitions,
        'type': 'object',
        'required': ['policies'],
        'additionalProperties': False,
        'properties': {
            'vars': {'type': 'object'},
            'policies': {
                'type': 'array',
                'additionalItems': False,
                'items': {'anyOf': resource_refs}
            }
        }
    }

    return schema
Beispiel #3
0
def generate(resource_types=()):
    resource_defs = {}
    definitions = {
        'resources': resource_defs,
        'iam-statement': {
            'additionalProperties':
            False,
            'type':
            'object',
            'properties': {
                'Sid': {
                    'type': 'string'
                },
                'Effect': {
                    'type': 'string',
                    'enum': ['Allow', 'Deny']
                },
                'Principal': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'object'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotPrincipal': {
                    'anyOf': [{
                        'type': 'object'
                    }, {
                        'type': 'array'
                    }]
                },
                'Action': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotAction': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'Resource': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotResource': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'Condition': {
                    'type': 'object'
                }
            },
            'required': ['Sid', 'Effect'],
            'oneOf': [{
                'required': ['Principal', 'Action', 'Resource']
            }, {
                'required': ['NotPrincipal', 'Action', 'Resource']
            }, {
                'required': ['Principal', 'NotAction', 'Resource']
            }, {
                'required': ['NotPrincipal', 'NotAction', 'Resource']
            }, {
                'required': ['Principal', 'Action', 'NotResource']
            }, {
                'required': ['NotPrincipal', 'Action', 'NotResource']
            }, {
                'required': ['Principal', 'NotAction', 'NotResource']
            }, {
                'required': ['NotPrincipal', 'NotAction', 'NotResource']
            }]
        },
        'filters': {
            'value': ValueFilter.schema,
            'event': EventFilter.schema,
            'age': AgeFilter.schema,
            # Shortcut form of value filter as k=v
            'valuekv': {
                'type': 'object',
                'minProperties': 1,
                'maxProperties': 1
            },
        },
        'policy': {
            'type': 'object',
            'required': ['name', 'resource'],
            'additionalProperties': False,
            'properties': {
                'name': {
                    'type': 'string',
                    'pattern': "^[A-z][A-z0-9]*(-[A-z0-9]+)*$"
                },
                'region': {
                    'type': 'string'
                },
                'resource': {
                    'type': 'string'
                },
                'max-resources': {
                    'type': 'integer'
                },
                'comment': {
                    'type': 'string'
                },
                'comments': {
                    'type': 'string'
                },
                'description': {
                    'type': 'string'
                },
                'tags': {
                    'type': 'array',
                    'items': {
                        'type': 'string'
                    }
                },
                'mode': {
                    '$ref': '#/definitions/policy-mode'
                },
                'source': {
                    'enum': ['describe', 'config']
                },
                'actions': {
                    'type': 'array',
                },
                'filters': {
                    'type': 'array'
                },
                #
                # unclear if this should be allowed, it kills resource
                # cache coherency between policies, and we need to
                # generalize server side query mechanisms, currently
                # this only for ec2 instance queries. limitations
                # in json schema inheritance prevent us from doing this
                # on a type specific basis http://goo.gl/8UyRvQ
                'query': {
                    'type': 'array',
                    'items': {
                        'type': 'object',
                        'minProperties': 1,
                        'maxProperties': 1
                    }
                }
            },
        },
        'policy-mode': {
            'anyOf': [e.schema for _, e in execution.items()],
        }
    }

    resource_refs = []
    for cloud_name, cloud_type in clouds.items():
        for type_name, resource_type in cloud_type.resources.items():
            if resource_types and type_name not in resource_types:
                continue
            alias_name = None
            r_type_name = "%s.%s" % (cloud_name, type_name)
            if cloud_name == 'aws':
                alias_name = type_name
            resource_refs.append(
                process_resource(r_type_name, resource_type, resource_defs,
                                 alias_name))

    schema = {
        '$schema': 'http://json-schema.org/schema#',
        'id': 'http://schema.cloudcustodian.io/v0/custodian.json',
        'definitions': definitions,
        'type': 'object',
        'required': ['policies'],
        'additionalProperties': False,
        'properties': {
            'vars': {
                'type': 'object'
            },
            'policies': {
                'type': 'array',
                'additionalItems': False,
                'items': {
                    'anyOf': resource_refs
                }
            }
        }
    }

    return schema
Beispiel #4
0
def generate(resource_types=()):
    resource_defs = {}
    definitions = {
        'resources': resource_defs,
        'string_dict': {
            "type": "object",
            "patternProperties": {
                "*": {
                    "type": "string"
                },
            },
        },
        'basic_dict': {
            "type": "object",
            "patternProperties": {
                "*": {
                    'oneOf': [
                        {
                            "type": "string"
                        },
                        {
                            "type": "boolean"
                        },
                        {
                            "type": "number"
                        },
                    ],
                }
            },
        },
        'iam-statement': {
            'additionalProperties':
            False,
            'type':
            'object',
            'properties': {
                'Sid': {
                    'type': 'string'
                },
                'Effect': {
                    'type': 'string',
                    'enum': ['Allow', 'Deny']
                },
                'Principal': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'object'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotPrincipal': {
                    'anyOf': [{
                        'type': 'object'
                    }, {
                        'type': 'array'
                    }]
                },
                'Action': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotAction': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'Resource': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotResource': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'Condition': {
                    'type': 'object'
                }
            },
            'required': ['Sid', 'Effect'],
            'oneOf': [{
                'required': ['Principal', 'Action', 'Resource']
            }, {
                'required': ['NotPrincipal', 'Action', 'Resource']
            }, {
                'required': ['Principal', 'NotAction', 'Resource']
            }, {
                'required': ['NotPrincipal', 'NotAction', 'Resource']
            }, {
                'required': ['Principal', 'Action', 'NotResource']
            }, {
                'required': ['NotPrincipal', 'Action', 'NotResource']
            }, {
                'required': ['Principal', 'NotAction', 'NotResource']
            }, {
                'required': ['NotPrincipal', 'NotAction', 'NotResource']
            }]
        },
        'actions': {},
        'filters': {
            'value': ValueFilter.schema,
            'event': EventFilter.schema,
            'age': AgeFilter.schema,
            # Shortcut form of value filter as k=v
            'valuekv': {
                'type': 'object',
                'additionalProperties': {
                    'oneOf': [{
                        'type': 'number'
                    }, {
                        'type': 'null'
                    }, {
                        'type': 'array',
                        'maxItems': 0
                    }, {
                        'type': 'string'
                    }, {
                        'type': 'boolean'
                    }]
                },
                'minProperties': 1,
                'maxProperties': 1
            },
        },
        'filters_common': {
            'comparison_operators': {
                'enum': list(OPERATORS.keys())
            },
            'value_types': {
                'enum': VALUE_TYPES
            },
            'value_from': ValuesFrom.schema,
            'value': {
                'oneOf': [{
                    'type': 'array'
                }, {
                    'type': 'string'
                }, {
                    'type': 'boolean'
                }, {
                    'type': 'number'
                }, {
                    'type': 'null'
                }]
            },
        },
        'policy': {
            'type': 'object',
            'required': ['name', 'resource'],
            'additionalProperties': False,
            'properties': {
                'name': {
                    'type': 'string',
                    'pattern': "^[A-z][A-z0-9]*(-[A-z0-9]+)*$"
                },
                'conditions': {
                    'type': 'array',
                    'items': {
                        'anyOf': [{
                            'type': 'object',
                            'additionalProperties': False,
                            'properties': {
                                'or': {
                                    '$ref':
                                    '#/definitions/policy/properties/conditions'
                                }
                            }
                        }, {
                            'type': 'object',
                            'additionalProperties': False,
                            'properties': {
                                'not': {
                                    '$ref':
                                    '#/definitions/policy/properties/conditions'
                                }
                            }
                        }, {
                            'type': 'object',
                            'additionalProperties': False,
                            'properties': {
                                'and': {
                                    '$ref':
                                    '#/definitions/policy/properties/conditions'
                                }
                            }
                        }, {
                            '$ref': '#/definitions/filters/value'
                        }, {
                            '$ref': '#/definitions/filters/event'
                        }, {
                            '$ref': '#/definitions/filters/valuekv'
                        }]
                    }
                },
                # these should be deprecated for conditions
                'region': {
                    'type': 'string'
                },
                'tz': {
                    'type': 'string'
                },
                'start': {
                    'format': 'date-time'
                },
                'end': {
                    'format': 'date-time'
                },
                'resource': {
                    'type': 'string'
                },
                'max-resources': {
                    'anyOf': [{
                        'type': 'integer',
                        'minimum': 1
                    }, {
                        '$ref': '#/definitions/max-resources-properties'
                    }]
                },
                'max-resources-percent': {
                    'type': 'number',
                    'minimum': 0,
                    'maximum': 100
                },
                'comment': {
                    'type': 'string'
                },
                'comments': {
                    'type': 'string'
                },
                'description': {
                    'type': 'string'
                },
                'tags': {
                    'type': 'array',
                    'items': {
                        'type': 'string'
                    }
                },
                'mode': {
                    '$ref': '#/definitions/policy-mode'
                },
                'source': {
                    'enum': [
                        'describe', 'config', 'inventory', 'resource-graph',
                        'disk', 'static'
                    ]
                },
                'actions': {
                    'type': 'array',
                },
                'filters': {
                    'type': 'array'
                },
                #
                # TODO: source queries should really move under
                # source. This was initially used for describe sources
                # to expose server side query mechanisms, however its
                # important to note it also prevents resource cache
                # utilization between policies that have different
                # queries.
                'query': {
                    'type': 'array',
                    'items': {
                        'type': 'object'
                    }
                }
            },
        },
        'policy-mode': {
            'anyOf': [e.schema for _, e in execution.items()],
        },
        'max-resources-properties': {
            'type': 'object',
            'additionalProperties': False,
            'properties': {
                'amount': {
                    "type": 'integer',
                    'minimum': 1
                },
                'op': {
                    'enum': ['or', 'and']
                },
                'percent': {
                    'type': 'number',
                    'minimum': 0,
                    'maximum': 100
                }
            }
        }
    }

    resource_refs = []
    for cloud_name, cloud_type in sorted(clouds.items()):
        for type_name, resource_type in sorted(cloud_type.resources.items()):
            r_type_name = "%s.%s" % (cloud_name, type_name)
            if resource_types and r_type_name not in resource_types:
                if not resource_type.type_aliases:
                    continue
                elif not {
                        "%s.%s" % (cloud_name, ralias)
                        for ralias in resource_type.type_aliases
                }.intersection(resource_types):
                    continue

            aliases = []
            if resource_type.type_aliases:
                aliases.extend([
                    "%s.%s" % (cloud_name, a)
                    for a in resource_type.type_aliases
                ])
                # aws gets legacy aliases with no cloud prefix
                if cloud_name == 'aws':
                    aliases.extend(resource_type.type_aliases)

            # aws gets additional alias for default name
            if cloud_name == 'aws':
                aliases.append(type_name)

            resource_refs.append(
                process_resource(r_type_name, resource_type, resource_defs,
                                 aliases, definitions, cloud_name))

    schema = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        'id': 'http://schema.cloudcustodian.io/v0/custodian.json',
        'definitions': definitions,
        'type': 'object',
        'required': ['policies'],
        'additionalProperties': False,
        'properties': {
            'vars': {
                'type': 'object'
            },
            'policies': {
                'type': 'array',
                'additionalItems': False,
                'items': {
                    'anyOf': resource_refs
                }
            }
        }
    }

    # allow empty policies with lazy load
    if not resource_refs:
        schema['properties']['policies']['items'] = {'type': 'object'}
    return schema
Beispiel #5
0
def generate(resource_types=()):
    resource_defs = {}
    definitions = {
        'resources': resource_defs,
        'iam-statement': {
            'additionalProperties': False,
            'type': 'object',
            'properties': {
                'Sid': {'type': 'string'},
                'Effect': {'type': 'string', 'enum': ['Allow', 'Deny']},
                'Principal': {'anyOf': [
                    {'type': 'string'},
                    {'type': 'object'}, {'type': 'array'}]},
                'NotPrincipal': {'anyOf': [{'type': 'object'}, {'type': 'array'}]},
                'Action': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'NotAction': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'Resource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'NotResource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'Condition': {'type': 'object'}
            },
            'required': ['Sid', 'Effect'],
            'oneOf': [
                {'required': ['Principal', 'Action', 'Resource']},
                {'required': ['NotPrincipal', 'Action', 'Resource']},
                {'required': ['Principal', 'NotAction', 'Resource']},
                {'required': ['NotPrincipal', 'NotAction', 'Resource']},
                {'required': ['Principal', 'Action', 'NotResource']},
                {'required': ['NotPrincipal', 'Action', 'NotResource']},
                {'required': ['Principal', 'NotAction', 'NotResource']},
                {'required': ['NotPrincipal', 'NotAction', 'NotResource']}
            ]
        },
        'actions': {},
        'filters': {
            'value': ValueFilter.schema,
            'event': EventFilter.schema,
            'age': AgeFilter.schema,
            # Shortcut form of value filter as k=v
            'valuekv': {
                'type': 'object',
                'minProperties': 1,
                'maxProperties': 1},
        },

        'policy': {
            'type': 'object',
            'required': ['name', 'resource'],
            'additionalProperties': False,
            'properties': {
                'name': {
                    'type': 'string',
                    'pattern': "^[A-z][A-z0-9]*(-[A-z0-9]+)*$"},
                'region': {'type': 'string'},
                'tz': {'type': 'string'},
                'start': {'format': 'date-time'},
                'end': {'format': 'date-time'},
                'resource': {'type': 'string'},
                'max-resources': {'type': 'integer', 'minimum': 1},
                'max-resources-percent': {'type': 'number', 'minimum': 0, 'maximum': 100},
                'comment': {'type': 'string'},
                'comments': {'type': 'string'},
                'description': {'type': 'string'},
                'tags': {'type': 'array', 'items': {'type': 'string'}},
                'mode': {'$ref': '#/definitions/policy-mode'},
                'source': {'enum': ['describe', 'config']},
                'actions': {
                    'type': 'array',
                },
                'filters': {
                    'type': 'array'
                },
                #
                # unclear if this should be allowed, it kills resource
                # cache coherency between policies, and we need to
                # generalize server side query mechanisms, currently
                # this only for ec2 instance queries. limitations
                # in json schema inheritance prevent us from doing this
                # on a type specific basis http://goo.gl/8UyRvQ
                'query': {
                    'type': 'array', 'items': {
                        'type': 'object',
                        'minProperties': 1,
                        'maxProperties': 1}}
            },
        },
        'policy-mode': {
            'anyOf': [e.schema for _, e in execution.items()],
        }
    }

    resource_refs = []
    for cloud_name, cloud_type in clouds.items():
        for type_name, resource_type in cloud_type.resources.items():
            if resource_types and type_name not in resource_types:
                continue
            alias_name = None
            r_type_name = "%s.%s" % (cloud_name, type_name)
            if cloud_name == 'aws':
                alias_name = type_name
            resource_refs.append(
                process_resource(
                    r_type_name,
                    resource_type,
                    resource_defs,
                    alias_name,
                    definitions
                ))

    schema = {
        '$schema': 'http://json-schema.org/schema#',
        'id': 'http://schema.cloudcustodian.io/v0/custodian.json',
        'definitions': definitions,
        'type': 'object',
        'required': ['policies'],
        'additionalProperties': False,
        'properties': {
            'vars': {'type': 'object'},
            'policies': {
                'type': 'array',
                'additionalItems': False,
                'items': {'anyOf': resource_refs}
            }
        }
    }

    return schema
Beispiel #6
0
def generate(resource_types=()):
    resource_defs = {}
    definitions = {
        'resources': resource_defs,
        'iam-statement': {
            'additionalProperties':
            False,
            'type':
            'object',
            'properties': {
                'Sid': {
                    'type': 'string'
                },
                'Effect': {
                    'type': 'string',
                    'enum': ['Allow', 'Deny']
                },
                'Principal': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'object'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotPrincipal': {
                    'anyOf': [{
                        'type': 'object'
                    }, {
                        'type': 'array'
                    }]
                },
                'Action': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotAction': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'Resource': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'NotResource': {
                    'anyOf': [{
                        'type': 'string'
                    }, {
                        'type': 'array'
                    }]
                },
                'Condition': {
                    'type': 'object'
                }
            },
            'required': ['Sid', 'Effect'],
            'oneOf': [{
                'required': ['Principal', 'Action', 'Resource']
            }, {
                'required': ['NotPrincipal', 'Action', 'Resource']
            }, {
                'required': ['Principal', 'NotAction', 'Resource']
            }, {
                'required': ['NotPrincipal', 'NotAction', 'Resource']
            }, {
                'required': ['Principal', 'Action', 'NotResource']
            }, {
                'required': ['NotPrincipal', 'Action', 'NotResource']
            }, {
                'required': ['Principal', 'NotAction', 'NotResource']
            }, {
                'required': ['NotPrincipal', 'NotAction', 'NotResource']
            }]
        },
        'actions': {},
        'filters': {
            'value': ValueFilter.schema,
            'event': EventFilter.schema,
            'age': AgeFilter.schema,
            # Shortcut form of value filter as k=v
            'valuekv': {
                'type': 'object',
                'minProperties': 1,
                'maxProperties': 1
            },
        },
        'filters_common': {
            'comparison_operators': {
                'enum': list(OPERATORS.keys())
            },
            'value_types': {
                'enum': VALUE_TYPES
            },
            'value_from': ValuesFrom.schema,
            'value': {
                'oneOf': [{
                    'type': 'array'
                }, {
                    'type': 'string'
                }, {
                    'type': 'boolean'
                }, {
                    'type': 'number'
                }, {
                    'type': 'null'
                }]
            },
        },
        'policy': {
            'type': 'object',
            'required': ['name', 'resource'],
            'additionalProperties': False,
            'properties': {
                'name': {
                    'type': 'string',
                    'pattern': "^[A-z][A-z0-9]*(-[A-z0-9]+)*$"
                },
                'region': {
                    'type': 'string'
                },
                'tz': {
                    'type': 'string'
                },
                'start': {
                    'format': 'date-time'
                },
                'end': {
                    'format': 'date-time'
                },
                'resource': {
                    'type': 'string'
                },
                'max-resources': {
                    'anyOf': [{
                        'type': 'integer',
                        'minimum': 1
                    }, {
                        '$ref': '#/definitions/max-resources-properties'
                    }]
                },
                'max-resources-percent': {
                    'type': 'number',
                    'minimum': 0,
                    'maximum': 100
                },
                'comment': {
                    'type': 'string'
                },
                'comments': {
                    'type': 'string'
                },
                'description': {
                    'type': 'string'
                },
                'tags': {
                    'type': 'array',
                    'items': {
                        'type': 'string'
                    }
                },
                'mode': {
                    '$ref': '#/definitions/policy-mode'
                },
                'source': {
                    'enum': ['describe', 'config']
                },
                'actions': {
                    'type': 'array',
                },
                'filters': {
                    'type': 'array'
                },
                #
                # unclear if this should be allowed, it kills resource
                # cache coherency between policies, and we need to
                # generalize server side query mechanisms, currently
                # this only for ec2 instance queries. limitations
                # in json schema inheritance prevent us from doing this
                # on a type specific basis
                # https://stackoverflow.com/questions/22689900/json-schema-allof-with-additionalproperties
                'query': {
                    'type': 'array',
                    'items': {
                        'type': 'object'
                    }
                }
            },
        },
        'policy-mode': {
            'anyOf': [e.schema for _, e in execution.items()],
        },
        'max-resources-properties': {
            'type': 'object',
            'properties': {
                'amount': {
                    "type": 'integer',
                    'minimum': 1
                },
                'op': {
                    'enum': ['or', 'and']
                },
                'percent': {
                    'type': 'number',
                    'minimum': 0,
                    'maximum': 100
                }
            }
        }
    }

    resource_refs = []
    for cloud_name, cloud_type in clouds.items():
        for type_name, resource_type in cloud_type.resources.items():
            if resource_types and type_name not in resource_types:
                continue
            alias_name = None
            r_type_name = "%s.%s" % (cloud_name, type_name)
            if cloud_name == 'aws':
                alias_name = type_name
            resource_refs.append(
                process_resource(r_type_name, resource_type, resource_defs,
                                 alias_name, definitions))

    schema = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        'id': 'http://schema.cloudcustodian.io/v0/custodian.json',
        'definitions': definitions,
        'type': 'object',
        'required': ['policies'],
        'additionalProperties': False,
        'properties': {
            'vars': {
                'type': 'object'
            },
            'policies': {
                'type': 'array',
                'additionalItems': False,
                'items': {
                    'anyOf': resource_refs
                }
            }
        }
    }

    return schema