Writing

command.write_policy

writing.sid_group

sid_group indicates that this is a collection of policy-related data organized by their SIDs

class policy_sentry.writing.sid_group.SidGroup

This class is critical to the creation of least privilege policies. It uses the SIDs as namespaces. The namespaces follow this format:

{Servicename}{Accesslevel}{Resourcetypename}

So, a resulting statement’s SID might look like ‘S3ListBucket’

If a condition key is supplied (like s3:RequestJob), the SID string will be significantly longer. It will resemble this format:

{Servicename}{Accesslevel}{Resourcetypename}{Conditionkeystring}{Conditiontypestring}{Conditionkeyvalue}
For example: EC2 write actions on the security-group resource, using the following condition map:
“Condition”: {
“StringEquals”: {“ec2:ResourceTag/Owner”: “${aws:username}”}

}

The resulting SID would be:
Ec2WriteSecuritygroupResourcetagownerStringequalsAwsusername
Or, for actions that support wildcard ARNs only, an example could be:
Ec2WriteMultResourcetagownerStringequalsAwsusername
add_action_without_resource_constraint(action)

This handles the cases where certain actions do not handle resource constraints - either by AWS, or for flexibility when adding dependent actions.

Parameters:action – The single action to add to the MultMultNone SID namespace. For instance, s3:ListAllMyBuckets
add_by_arn_and_access_level(db_session, arn_list, access_level, conditions_block=None)

This adds the user-supplied ARN(s), service prefixes, access levels, and condition keys (if applicable) given by the user. It derives the list of IAM actions based on the user’s requested ARNs and access levels.

Parameters:
  • db_session – SQLAlchemy database session
  • arn_list – Just a list of resource ARNs.
  • access_level – “Read”, “List”, “Tagging”, “Write”, or “Permissions management”
  • conditions_block – Optionally, a condition block with one or more conditions
add_by_list_of_actions(db_session, supplied_actions)

Takes a list of actions, queries the database for corresponding arns, adds them to the object.

Parameters:
  • db_session – SQLAlchemy database session object
  • supplied_actions – A list of supplied actions
add_wildcard_only_actions(db_session, provided_wildcard_actions)

Given a list of IAM actions, add individual IAM Actions that do not support resource constraints to the MultMultNone SID

Parameters:
  • db_session – SQLAlchemy database session
  • provided_wildcard_actions – list actions provided by the user.
add_wildcard_only_actions_matching_services_and_access_level(db_session, services, access_level)
param db_session:
 SQLAlchemy database session
param services:A list of AWS services
Parameters:access_level – An access level as it is written in the database, such as ‘Read’, ‘Write’, ‘List’, ‘Permisssions management’, or ‘Tagging’
get_rendered_policy(db_session, minimize=None)

Get the JSON rendered policy

Parameters:
  • db_session – SQLAlchemy database session
  • minimize – Reduce the character count of policies without creating overlap with other action names
Return type:

dict

get_sid(sid)

Get a single group by the SID identifier

get_sid_group()

Get the whole SID group as JSON

get_universal_conditions()

Get the universal conditions maps back as a dict

Return type:dict
list_sids()

Get a list of all of them by their identifiers

Return type:list
process_template(db_session, cfg, minimize=None)

Process the Policy Sentry template as a dict. This auto-detects whether or not the file is in CRUD mode or Actions mode.

Parameters:
  • db_session – SQLAlchemy database session object
  • cfg – The loaded YAML as a dict. Must follow Policy Sentry dictated format.
  • minimize – Minimize the resulting statement with safe usage of wildcards to reduce policy length. Set this to the character length you want - for example, 0, or 4. Defaults to none.
remove_actions_duplicated_in_wildcard_arn()

Removes actions from the object that are in a resource-specific ARN, as well as the * resource. For example, if ssm:GetParameter is restricted to a specific parameter path, as well as *, then we want to remove the * option to force least privilege.

remove_actions_not_matching_these(actions_to_keep)
Parameters:actions_to_keep – A list of actions to leave in the policy. All actions not in this list are removed.
remove_sids_with_empty_action_lists()
Now that we’ve removed a bunch of actions, if there are SID groups without any actions,
remove them so we don’t get SIDs with empty action lists
policy_sentry.writing.sid_group.create_policy_sid_namespace(service, access_level, resource_type_name, condition_block=None)

Simply generates the SID name. The SID groups ARN types that share an access level.

For example, S3 objects vs. SSM Parameter have different ARN types - as do S3 objects vs S3 buckets. That’s how we choose to group them.

Parameters:
  • service – “ssm”
  • access_level – “Read”
  • resource_type_name – “parameter”
  • condition_block – {“condition_key_string”: “ec2:ResourceTag/purpose”, “condition_type_string”: “StringEquals”, “condition_value”: “test”}
Returns:

SsmReadParameter

Return type:

str

policy_sentry.writing.sid_group.remove_actions_that_are_not_wildcard_arn_only(db_session, actions_list)

Given a list of actions, remove the ones that CAN be restricted to ARNs, leaving only the ones that cannot.

Parameters:
  • db_session – SQL Alchemy database session object
  • actions_list – A list of actions
Returns:

An updated list of actions

Return type:

list

writing.template

Templates for the policy_sentry YML files. These can be used for generating policies

policy_sentry.writing.template.create_actions_template(name)

Generate the Actions YML template with Jinja2

policy_sentry.writing.template.create_crud_template(name)

Generate the CRUD YML Template with Jinja2

policy_sentry.writing.template.get_actions_template_dict()

Get the Actions template in dict format.

policy_sentry.writing.template.get_crud_template_dict()

Generate the CRUD template in dict format

writing.validate

Validation for the Policy Sentry YML Templates.

policy_sentry.writing.validate.check(conf_schema, conf)

Validates a user-supplied JSON vs a defined schema. :param conf_schema: The Schema object that defines the required structure. :param conf: The user-supplied schema to validate against the required structure.

policy_sentry.writing.validate.check_actions_schema(cfg)

Determines whether the user-provided config matches the required schema for Actions mode

policy_sentry.writing.validate.check_crud_schema(cfg)

Determines whether the user-provided config matches the required schema for CRUD mode

policy_sentry.writing.validate.validate_condition_block(condition_block)
Parameters:condition_block – {“condition_key_string”: “ec2:ResourceTag/purpose”, “condition_type_string”: “StringEquals”, “condition_value”: “test”}
Returns:

writing.minimize

Functions for Minimizing statements, heavily borrowed from policyuniverse. https://github.com/Netflix-Skunkworks/policyuniverse/

IAM Policies have character limits, which apply to individual policies, and there are also limits on the total aggregate policy sizes. As such, it is not possible to use exhaustive list of explicit IAM actions. To have granular control of specific IAM policies, we must use wildcards on IAM Actions, only in a programmatic manner.

This is typically performed by humans by reducing policies to s3:Get*, ec2:Describe*, and other approaches of the sort.

Netflix’s PolicyUniverse has address

https://aws.amazon.com/iam/faqs/ Q: How many policies can I attach to an IAM role? * For inline policies: You can add as many inline policies as you want to a user, role, or group, but

the total aggregate policy size (the sum size of all inline policies) per entity cannot exceed the following limits: - User policy size cannot exceed 2,048 characters. - Role policy size cannot exceed 10,240 characters. - Group policy size cannot exceed 5,120 characters.
  • For managed policies: You can add up to 10 managed policies to a user, role, or group.
  • The size of each managed policy cannot exceed 6,144 characters.
policy_sentry.writing.minimize.check_min_permission_length(permission, minchars=None)

Adapted version of policyuniverse’s _check_permission_length. We are commenting out the skipping prefix message https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L111

policy_sentry.writing.minimize.get_denied_prefixes_from_desired(desired_actions, all_actions)

Adapted version of policyuniverse’s _get_denied_prefixes_from_desired, here: https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L101

policy_sentry.writing.minimize.minimize_statement_actions(desired_actions, all_actions, minchars=None)

This is a condensed version of policyuniverse’s minimize_statement_actions, changed for our purposes. https://github.com/Netflix-Skunkworks/policyuniverse/blob/master/policyuniverse/expander_minimizer.py#L123