Port RuleDefaults to DocumentedRuleDefaults

In preparation for implementaing basic default roles[1] within
Barbican moving RuleDefault to DocumentedRuleDefault in policy
files.

Route to policy work being updated and tracked in wiki[2].

[1] -
https://github.com/openstack/keystone-specs/blob/master/specs/keystone/rocky/define-default-roles.rst
[2] - https://wiki.openstack.org/wiki/Barbican/Policy

Co-Authored-By: Juan Antonio Osorio Robles <jaosorior@redhat.com>
Change-Id: I73dd0cf8a89dc24a44b6bc2151d95df632932ccc
This commit is contained in:
Harry Rybacki 2018-06-13 16:11:32 -04:00 committed by Juan Antonio Osorio Robles
parent 661386a517
commit 4d58ac8ddc
11 changed files with 685 additions and 173 deletions

View File

@ -12,25 +12,98 @@
from oslo_policy import policy from oslo_policy import policy
# FIXME(hrybacki): Repetitive check strings: Port to simpler checks
# - secret_acls:delete, secret_acls:put_patch
# - container_acls:delete container_acls:put_patch
rules = [ rules = [
policy.RuleDefault('secret_acls:put_patch', policy.DocumentedRuleDefault(
'rule:secret_project_admin or ' name='secret_acls:get',
'rule:secret_project_creator'), check_str='rule:all_but_audit and rule:secret_project_match',
policy.RuleDefault('secret_acls:delete', scope_types=[],
'rule:secret_project_admin or ' description='Retrieve the ACL settings for a given secret.'
'rule:secret_project_creator'), 'If no ACL is defined for that secret, then Default ACL '
policy.RuleDefault('secret_acls:get', 'is returned.',
'rule:all_but_audit and ' operations=[
'rule:secret_project_match'), {
policy.RuleDefault('container_acls:put_patch', 'path': '/v1/secrets/{secret-id}/acl',
'rule:container_project_admin or ' 'method': 'GET'
'rule:container_project_creator'), },
policy.RuleDefault('container_acls:delete', ]
'rule:container_project_admin or ' ),
'rule:container_project_creator'), policy.DocumentedRuleDefault(
policy.RuleDefault('container_acls:get', name='secret_acls:delete',
'rule:all_but_audit and rule:container_project_match'), check_str='rule:secret_project_admin or rule:secret_project_creator',
scope_types=[],
description='Delete the ACL settings for a given secret.',
operations=[
{
'path': '/v1/secrets/{secret-id}/acl',
'method': 'DELETE'
},
]
),
policy.DocumentedRuleDefault(
name='secret_acls:put_patch',
check_str='rule:secret_project_admin or rule:secret_project_creator',
scope_types=[],
description='Create new, replaces, or updates existing ACL for a ' +
'given secret.',
operations=[
{
'path': '/v1/secrets/{secret-id}/acl',
'method': 'PUT'
},
{
'path': '/v1/secrets/{secret-id}/acl',
'method': 'PATCH'
},
]
),
policy.DocumentedRuleDefault(
name='container_acls:get',
check_str='rule:all_but_audit and rule:container_project_match',
scope_types=[],
description='Retrieve the ACL settings for a given container.',
operations=[
{
'path': '/v1/containers/{container-id}/acl',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='container_acls:delete',
check_str='rule:container_project_admin or ' +
'rule:container_project_creator',
scope_types=[],
description='Delete ACL for a given container. No content is returned '
'in the case of successful deletion.',
operations=[
{
'path': '/v1/containers/{container-id}/acl',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name='container_acls:put_patch',
check_str='rule:container_project_admin or ' +
'rule:container_project_creator',
scope_types=[],
description='Create new or replaces existing ACL for a given '
'container.',
operations=[
{
'path': '/v1/containers/{container-id}/acl',
'method': 'PUT'
},
{
'path': '/v1/containers/{container-id}/acl',
'method': 'PATCH'
}
]
),
] ]

View File

@ -14,58 +14,81 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('admin', policy.RuleDefault(
'role:admin'), name='admin',
policy.RuleDefault('observer', check_str='role:admin'),
'role:observer'), policy.RuleDefault(
policy.RuleDefault('creator', name='observer',
'role:creator'), check_str='role:observer'),
policy.RuleDefault('audit', policy.RuleDefault(
'role:audit'), name='creator',
policy.RuleDefault('service_admin', check_str='role:creator'),
'role:key-manager:service-admin'), policy.RuleDefault(
policy.RuleDefault('admin_or_creator', name='audit',
'rule:admin or rule:creator'), check_str='role:audit'),
policy.RuleDefault('all_but_audit', policy.RuleDefault(
'rule:admin or rule:observer or rule:creator'), name='service_admin',
policy.RuleDefault('all_users', check_str='role:key-manager:service-admin'),
'rule:admin or rule:observer or rule:creator or ' policy.RuleDefault(
'rule:audit or rule:service_admin'), name='admin_or_creator',
policy.RuleDefault('secret_project_match', check_str='rule:admin or rule:creator'),
'project:%(target.secret.project_id)s'), policy.RuleDefault(
policy.RuleDefault('secret_acl_read', name='all_but_audit',
"'read':%(target.secret.read)s"), check_str='rule:admin or rule:observer or rule:creator'),
policy.RuleDefault('secret_private_read', policy.RuleDefault(
"'False':%(target.secret.read_project_access)s"), name='all_users',
policy.RuleDefault('secret_creator_user', check_str='rule:admin or rule:observer or rule:creator or ' +
"user:%(target.secret.creator_id)s"), 'rule:audit or rule:service_admin'),
policy.RuleDefault('container_project_match', policy.RuleDefault(
"project:%(target.container.project_id)s"), name='secret_project_match',
policy.RuleDefault('container_acl_read', check_str='project:%(target.secret.project_id)s'),
"'read':%(target.container.read)s"), policy.RuleDefault(
policy.RuleDefault('container_private_read', name='secret_acl_read',
"'False':%(target.container.read_project_access)s"), check_str="'read':%(target.secret.read)s"),
policy.RuleDefault('container_creator_user', policy.RuleDefault(
"user:%(target.container.creator_id)s"), name='secret_private_read',
policy.RuleDefault('secret_non_private_read', check_str="'False':%(target.secret.read_project_access)s"),
"rule:all_users and rule:secret_project_match and " policy.RuleDefault(
"not rule:secret_private_read"), name='secret_creator_user',
policy.RuleDefault('secret_decrypt_non_private_read', check_str="user:%(target.secret.creator_id)s"),
"rule:all_but_audit and rule:secret_project_match and " policy.RuleDefault(
"not rule:secret_private_read"), name='container_project_match',
policy.RuleDefault('container_non_private_read', check_str="project:%(target.container.project_id)s"),
"rule:all_users and rule:container_project_match and " policy.RuleDefault(
"not rule:container_private_read"), name='container_acl_read',
policy.RuleDefault('secret_project_admin', check_str="'read':%(target.container.read)s"),
"rule:admin and rule:secret_project_match"), policy.RuleDefault(
policy.RuleDefault('secret_project_creator', name='container_private_read',
"rule:creator and rule:secret_project_match and " check_str="'False':%(target.container.read_project_access)s"),
"rule:secret_creator_user"), policy.RuleDefault(
policy.RuleDefault('container_project_admin', name='container_creator_user',
"rule:admin and rule:container_project_match"), check_str="user:%(target.container.creator_id)s"),
policy.RuleDefault('container_project_creator', policy.RuleDefault(
"rule:creator and rule:container_project_match and " name='secret_non_private_read',
"rule:container_creator_user"), check_str="rule:all_users and rule:secret_project_match and not " +
"rule:secret_private_read"),
policy.RuleDefault(
name='secret_decrypt_non_private_read',
check_str="rule:all_but_audit and rule:secret_project_match and not " +
"rule:secret_private_read"),
policy.RuleDefault(
name='container_non_private_read',
check_str="rule:all_users and rule:container_project_match and not " +
"rule:container_private_read"),
policy.RuleDefault(
name='secret_project_admin',
check_str="rule:admin and rule:secret_project_match"),
policy.RuleDefault(
name='secret_project_creator',
check_str="rule:creator and rule:secret_project_match and " +
"rule:secret_creator_user"),
policy.RuleDefault(
name='container_project_admin',
check_str="rule:admin and rule:container_project_match"),
policy.RuleDefault(
name='container_project_creator',
check_str="rule:creator and rule:container_project_match and " +
"rule:container_creator_user"),
] ]

View File

@ -12,30 +12,71 @@
from oslo_policy import policy from oslo_policy import policy
# FIXME(hrybacki): Note that the GET rules have the same check strings.
# The POST/DELETE rules also share the check stirngs.
# These can probably be turned into constants in base
rules = [ rules = [
policy.RuleDefault('consumer:get', policy.DocumentedRuleDefault(
'rule:admin or rule:observer or rule:creator or ' name='consumer:get',
'rule:audit or rule:container_non_private_read or ' check_str='rule:admin or rule:observer or rule:creator or ' +
'rule:container_project_creator or ' 'rule:audit or rule:container_non_private_read or ' +
'rule:container_project_admin or ' 'rule:container_project_creator or ' +
'rule:container_acl_read'), 'rule:container_project_admin or rule:container_acl_read',
policy.RuleDefault('consumers:get', scope_types=[],
'rule:admin or rule:observer or rule:creator or ' description='List a specific consumer for a given container.',
'rule:audit or rule:container_non_private_read or ' operations=[
'rule:container_project_creator or ' {
'rule:container_project_admin or ' 'path': '/v1/containers/{container-id}/consumers/' +
'rule:container_acl_read'), '{consumer-id}',
policy.RuleDefault('consumers:post', 'method': 'GET'
'rule:admin or rule:container_non_private_read or ' }
'rule:container_project_creator or ' ]
'rule:container_project_admin or ' ),
'rule:container_acl_read'), policy.DocumentedRuleDefault(
policy.RuleDefault('consumers:delete', name='consumers:get',
'rule:admin or rule:container_non_private_read or ' check_str='rule:admin or rule:observer or rule:creator or ' +
'rule:container_project_creator or ' 'rule:audit or rule:container_non_private_read or ' +
'rule:container_project_admin or ' 'rule:container_project_creator or ' +
'rule:container_acl_read'), 'rule:container_project_admin or rule:container_acl_read',
scope_types=[],
description='List a containers consumers.',
operations=[
{
'path': '/v1/containers/{container-id}/consumers',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='consumers:post',
check_str='rule:admin or rule:container_non_private_read or ' +
'rule:container_project_creator or ' +
'rule:container_project_admin or rule:container_acl_read',
scope_types=[],
description='Creates a consumer.',
operations=[
{
'path': '/v1/containers/{container-id}/consumers',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name='consumers:delete',
check_str='rule:admin or rule:container_non_private_read or ' +
'rule:container_project_creator or ' +
'rule:container_project_admin or rule:container_acl_read',
scope_types=[],
description='Deletes a consumer.',
operations=[
{
'path': '/v1/containers/{container-id}/consumers/' +
'{consumer-id}',
'method': 'DELETE'
}
]
),
] ]

View File

@ -14,22 +14,82 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('containers:post', policy.DocumentedRuleDefault(
'rule:admin_or_creator'), name='containers:post',
policy.RuleDefault('containers:get', check_str='rule:admin_or_creator',
'rule:all_but_audit'), scope_types=[],
policy.RuleDefault('container:get', description='Creates a container.',
'rule:container_non_private_read or ' operations=[
'rule:container_project_creator or ' {
'rule:container_project_admin or ' 'path': '/v1/containers',
'rule:container_acl_read'), 'method': 'POST'
policy.RuleDefault('container:delete', }
'rule:container_project_admin or ' ]
'rule:container_project_creator'), ),
policy.RuleDefault('container_secret:post', policy.DocumentedRuleDefault(
'rule:admin'), name='containers:get',
policy.RuleDefault('container_secret:delete', check_str='rule:all_but_audit',
'rule:admin'), scope_types=[],
description='Lists a projects containers.',
operations=[
{
'path': '/v1/containers',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='container:get',
check_str='rule:container_non_private_read or ' +
'rule:container_project_creator or ' +
'rule:container_project_admin or ' +
'rule:container_acl_read',
scope_types=[],
description='Retrieves a single container.',
operations=[
{
'path': '/v1/containers/{container-id}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='container:delete',
check_str='rule:container_project_admin or ' +
'rule:container_project_creator',
scope_types=[],
description='Deletes a container.',
operations=[
{
'path': '/v1/containers/{uuid}',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name='container_secret:post',
check_str='rule:admin',
scope_types=[],
description='Add a secret to an existing container.',
operations=[
{
'path': '/v1/containers/{container-id}/secrets',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name='container_secret:delete',
check_str='rule:admin',
scope_types=[],
description='Remove a secret from a container.',
operations=[
{
'path': '/v1/containers/{container-id}/secrets/{secret-id}',
'method': 'DELETE'
}
]
),
] ]

View File

@ -14,16 +14,66 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('orders:post', policy.DocumentedRuleDefault(
'rule:admin_or_creator'), name='orders:get',
policy.RuleDefault('orders:get', check_str='rule:all_but_audit',
'rule:all_but_audit'), scope_types=[],
policy.RuleDefault('orders:put', description='Gets list of all orders associated with a project.',
'rule:admin_or_creator'), operations=[
policy.RuleDefault('order:get', {
'rule:all_users'), 'path': '/v1/orders',
policy.RuleDefault('order:delete', 'method': 'GET'
'rule:admin'), }
]
),
policy.DocumentedRuleDefault(
name='orders:post',
check_str='rule:admin_or_creator',
scope_types=[],
description='Creates an order.',
operations=[
{
'path': '/v1/orders',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name='orders:put',
check_str='rule:admin_or_creator',
scope_types=[],
description='Unsupported method for the orders API.',
operations=[
{
'path': '/v1/orders',
'method': 'PUT'
}
]
),
policy.DocumentedRuleDefault(
name='order:get',
check_str='rule:all_users',
scope_types=[],
description='Retrieves an orders metadata.',
operations=[
{
'path': '/v1/orders/{order-id}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='order:delete',
check_str='rule:admin',
scope_types=[],
description='Deletes an order.',
operations=[
{
'path': '/v1/orders/{order-id}',
'method': 'DELETE'
}
],
)
] ]

View File

@ -14,14 +14,60 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('quotas:get', policy.DocumentedRuleDefault(
'rule:all_users'), name='quotas:get',
policy.RuleDefault('project_quotas:get', check_str='rule:all_users',
'rule:service_admin'), scope_types=[],
policy.RuleDefault('project_quotas:put', description='List quotas for the project the user belongs to.',
'rule:service_admin'), operations=[
policy.RuleDefault('project_quotas:delete', {
'rule:service_admin'), 'path': '/v1/quotas',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='project_quotas:get',
check_str='rule:service_admin',
scope_types=[],
description='List quotas for the specified project.',
operations=[
{
'path': '/v1/project-quotas',
'method': 'GET'
},
{
'path': '/v1/project-quotas/{uuid}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='project_quotas:put',
check_str='rule:service_admin',
scope_types=[],
description='Create or update the configured project quotas for '
'the project with the specified UUID.',
operations=[
{
'path': '/v1/project-quotas/{uuid}',
'method': 'PUT'
}
]
),
policy.DocumentedRuleDefault(
name='project_quotas:delete',
check_str='rule:service_admin',
scope_types=[],
description='Delete the project quotas configuration for the '
'project with the requested UUID.',
operations=[
{
'path': '/v1/quotas}',
'method': 'DELETE'
}
]
),
] ]

View File

@ -14,14 +14,66 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('secret_meta:get', policy.DocumentedRuleDefault(
'rule:all_but_audit'), name='secret_meta:get',
policy.RuleDefault('secret_meta:post', check_str='rule:all_but_audit',
'rule:admin_or_creator'), scope_types=[],
policy.RuleDefault('secret_meta:put', description='metadata/: Lists a secrets user-defined metadata. || ' +
'rule:admin_or_creator'), 'metadata/{key}: Retrieves a secrets user-added metadata.',
policy.RuleDefault('secret_meta:delete', operations=[
'rule:admin_or_creator'), {
'path': '/v1/secrets/{secret-id}/metadata',
'method': 'GET'
},
{
'path': '/v1/secrets/{secret-id}/metadata/{meta-key}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='secret_meta:post',
check_str='rule:admin_or_creator',
scope_types=[],
description='Adds a new key/value pair to the secrets user-defined ' +
'metadata.',
operations=[
{
'path': '/v1/secrets/{secret-id}/metadata/{meta-key}',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name='secret_meta:put',
check_str='rule:admin_or_creator',
scope_types=[],
description='metadata/: Sets the user-defined metadata for a secret ' +
'|| metadata/{key}: Updates an existing key/value pair ' +
'in the secrets user-defined metadata.',
operations=[
{
'path': '/v1/secrets/{secret-id}/metadata',
'method': 'PUT'
},
{
'path': '/v1/secrets/{secret-id}/metadata/{meta-key}',
'method': 'PUT'
}
]
),
policy.DocumentedRuleDefault(
name='secret_meta:delete',
check_str='rule:admin_or_creator',
scope_types=[],
description='Delete secret user-defined metadata by key.',
operations=[
{
'path': '/v1/secrets/{secret-id}/metadata/{meta-key}',
'method': 'DELETE'
}
]
),
] ]

View File

@ -14,26 +14,83 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('secret:decrypt', policy.DocumentedRuleDefault(
'rule:secret_decrypt_non_private_read or ' name='secret:decrypt',
'rule:secret_project_creator or ' check_str='rule:secret_decrypt_non_private_read or ' +
'rule:secret_project_admin or ' 'rule:secret_project_creator or ' +
'rule:secret_acl_read'), 'rule:secret_project_admin or rule:secret_acl_read',
policy.RuleDefault('secret:get', scope_types=[],
'rule:secret_non_private_read or ' description='Retrieve a secrets payload.',
'rule:secret_project_creator or ' operations=[
'rule:secret_project_admin or ' {
'rule:secret_acl_read'), 'path': '/v1/secrets/{uuid}/payload',
policy.RuleDefault('secret:put', 'method': 'GET'
'rule:admin_or_creator and ' }
'rule:secret_project_match'), ]
policy.RuleDefault('secret:delete', ),
'rule:secret_project_admin or ' policy.DocumentedRuleDefault(
'rule:secret_project_creator'), name='secret:get',
policy.RuleDefault('secrets:post', check_str='rule:secret_non_private_read or ' +
'rule:admin_or_creator'), 'rule:secret_project_creator or ' +
policy.RuleDefault('secrets:get', 'rule:secret_project_admin or rule:secret_acl_read',
'rule:all_but_audit'), scope_types=[],
description='Retrieves a secrets metadata.',
operations=[
{
'path': '/v1/secrets/{secret-id}',
'method': 'GET"'
}
]
),
policy.DocumentedRuleDefault(
name='secret:put',
check_str='rule:admin_or_creator and rule:secret_project_match',
scope_types=[],
description='Add the payload to an existing metadata-only secret.',
operations=[
{
'path': '/v1/secrets/{secret-id}',
'method': 'PUT'
}
]
),
policy.DocumentedRuleDefault(
name='secret:delete',
check_str='rule:secret_project_admin or ' +
'rule:secret_project_creator',
scope_types=[],
description='Delete a secret by uuid.',
operations=[
{
'path': '/v1/secrets/{secret-id}',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name='secrets:post',
check_str='rule:admin_or_creator',
scope_types=[],
description='Creates a Secret entity.',
operations=[
{
'path': '/v1/secrets',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name='secrets:get',
check_str='rule:all_but_audit',
scope_types=[],
description='Lists a projects secrets.',
operations=[
{
'path': '/v1/secrets',
'method': 'GET'
}
]
)
] ]

View File

@ -14,18 +14,82 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('secretstores:get', policy.DocumentedRuleDefault(
'rule:admin'), name='secretstores:get',
policy.RuleDefault('secretstores:get_global_default', check_str='rule:admin',
'rule:admin'), scope_types=[],
policy.RuleDefault('secretstores:get_preferred', description='Get list of available secret store backends.',
'rule:admin'), operations=[
policy.RuleDefault('secretstore_preferred:post', {
'rule:admin'), 'path': '/v1/secret-stores',
policy.RuleDefault('secretstore_preferred:delete', 'method': 'GET'
'rule:admin'), }
policy.RuleDefault('secretstore:get', ]
'rule:admin'), ),
policy.DocumentedRuleDefault(
name='secretstores:get_global_default',
check_str='rule:admin',
scope_types=[],
description='Get a reference to the secret store that is used as ' +
'default secret store backend for the deployment.',
operations=[
{
'path': '/v1/secret-stores/global-default',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='secretstores:get_preferred',
check_str='rule:admin',
scope_types=[],
description='Get a reference to the preferred secret store if ' +
'assigned previously.',
operations=[
{
'path': '/v1/secret-stores/preferred',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='secretstore_preferred:post',
check_str='rule:admin',
scope_types=[],
description='Set a secret store backend to be preferred store ' +
'backend for their project.',
operations=[
{
'path': '/v1/secret-stores/{ss-id}/preferred',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name='secretstore_preferred:delete',
check_str='rule:admin',
scope_types=[],
description='Remove preferred secret store backend setting for ' +
'their project.',
operations=[
{
'path': '/v1/secret-stores/{ss-id}/preferred',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name='secretstore:get',
check_str='rule:admin',
scope_types=[],
description='Get details of secret store by its ID.',
operations=[
{
'path': '/v1/secret-stores/{ss-id}',
'method': 'GET'
}
]
),
] ]

View File

@ -14,14 +14,55 @@ from oslo_policy import policy
rules = [ rules = [
policy.RuleDefault('transport_key:get', policy.DocumentedRuleDefault(
'rule:all_users'), name='transport_key:get',
policy.RuleDefault('transport_key:delete', check_str='rule:all_users',
'rule:admin'), scope_types=[],
policy.RuleDefault('transport_keys:get', description='Get a specific transport key.',
'rule:all_users'), operations=[
policy.RuleDefault('transport_keys:post', {
'rule:admin'), 'path': '/v1/transport_keys/{key-id}}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='transport_key:delete',
check_str='rule:admin',
scope_types=[],
description='Delete a specific transport key.',
operations=[
{
'path': '/v1/transport_keys/{key-id}',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name='transport_keys:get',
check_str='rule:all_users',
scope_types=[],
description='Get a list of all transport keys.',
operations=[
{
'path': '/v1/transport_keys',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name='transport_keys:post',
check_str='rule:admin',
scope_types=[],
description='Create a new transport key.',
operations=[
{
'path': '/v1/transport_keys',
'method': 'POST'
}
]
),
] ]

View File

@ -0,0 +1,5 @@
---
features:
- |
Port existing policy RuleDefault objects to the newer, more verbose
DocumentedRuleDefaults.