def iam_no_s3_list_validator(args: ResourceValidationArgs, report_violation: ReportViolation) -> None: if args.resource_type == "aws:iam/rolepolicy:RolePolicy" and "policy" in args.props: if "s3:ListBucket" in args.props["policy"]: report_violation( "You should not require s3:ListBucket permissions", None) s3_no_public_read = ResourceValidationPolicy( name="s3-no-public-read", description= "Prohibits setting the publicRead or publicReadWrite permission on AWS S3 buckets.", validate=s3_no_public_read_validator, ) iam_no_s3_list = ResourceValidationPolicy( name="iam_no_s3_list", description= "Prohibits setting the s3:ListBuckets permission in IAM policies", validate=iam_no_s3_list_validator, ) PolicyPack( name="aws-python", enforcement_level=EnforcementLevel.MANDATORY, policies=[ s3_no_public_read, iam_no_s3_list, ], )
def test_init_raises(self): self.assertRaises(TypeError, lambda: PolicyPack(None, [NOP_POLICY])) self.assertRaises(TypeError, lambda: PolicyPack("", [NOP_POLICY])) self.assertRaises(TypeError, lambda: PolicyPack(1, [NOP_POLICY])) self.assertRaises(TypeError, lambda: PolicyPack( ("a" * 100) + "a", [NOP_POLICY])) self.assertRaises(TypeError, lambda: PolicyPack("*", [NOP_POLICY])) self.assertRaises(TypeError, lambda: PolicyPack("policies", None)) self.assertRaises(TypeError, lambda: PolicyPack("policies", "")) self.assertRaises(TypeError, lambda: PolicyPack("policies", 1)) self.assertRaises(TypeError, lambda: PolicyPack("policies", [])) self.assertRaises(TypeError, lambda: PolicyPack("policies", [None])) self.assertRaises(TypeError, lambda: PolicyPack("policies", [""])) self.assertRaises(TypeError, lambda: PolicyPack("policies", [1])) self.assertRaises(TypeError, lambda: PolicyPack("policies", [NOP_POLICY], "")) self.assertRaises(TypeError, lambda: PolicyPack("policies", [NOP_POLICY], 1)) el = EnforcementLevel.ADVISORY self.assertRaises(TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, "")) self.assertRaises(TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, 1)) self.assertRaises(TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, [])) self.assertRaises( TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, {1: 1})) self.assertRaises( TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, {"p": None})) self.assertRaises( TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, {"p": ""})) self.assertRaises( TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, {"p": 1})) self.assertRaises( TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, {"p": []})) self.assertRaises( TypeError, lambda: PolicyPack("policies", [NOP_POLICY], el, {"p": { 1: 1 }}))
ReportViolation, ResourceValidationArgs, ResourceValidationPolicy, ) def storage_bucket_no_public_read_validator(args: ResourceValidationArgs, report_violation: ReportViolation): if args.resource_type == "gcp:storage/bucketACL:BucketACL" and "predefinedAcl" in args.props: acl = args.props["predefinedAcl"] if acl == "public-read" or acl == "public-read-write": report_violation( "Storage buckets acl cannot be set to public-read or public-read-write." ) storage_bucket_no_public_read = ResourceValidationPolicy( name="storage-bucket-no-public-read", description= "Prohibits setting the publicRead or publicReadWrite permission on GCP Storage buckets.", validate=storage_bucket_no_public_read_validator, ) PolicyPack( name="gcp-python", enforcement_level=EnforcementLevel.MANDATORY, policies=[ storage_bucket_no_public_read, ], )
for r in args.resources: verify(r) def verify(r): t = r.resource_type if t != "random:index/randomPet:RandomPet": return # Accessing `prefix` is expected to result in a policy violation because its value is unknown # during previews given the associated Pulumi program. print(r.props["prefix"]) PolicyPack( name="unknown-values-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ ResourceValidationPolicy( name="unknown-values-resource-validation", description="Accessing unknown values during preview results in a violation.", validate=validate_resource, ), StackValidationPolicy( name="unknown-values-stack-validation", description="Accessing unknown values during preview results in a violation.", validate=validate_stack, ), ], )
# Copyright 2016-2020, Pulumi Corporation. All rights reserved. from pulumi_policy import ( EnforcementLevel, PolicyPack, ReportViolation, ResourceValidationArgs, ResourceValidationPolicy, ) def randomuuid_no_keepers_validator(args: ResourceValidationArgs, report_violation: ReportViolation): if args.resource_type == "random:index/randomUuid:RandomUuid": if "keepers" not in args.props or not args.props["keepers"]: report_violation("RandomUuid must not have an empty 'keepers'.") randomuuid_no_keepers = ResourceValidationPolicy( name="randomuuid-no-keepers", description="Prohibits creating a RandomUuid without any 'keepers'.", validate=randomuuid_no_keepers_validator, ) PolicyPack( name="validate-resource-test-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[randomuuid_no_keepers], )
) #allowed port policy : not allow (> 1024) def compute_firewall_rule_validator(args: ResourceValidationArgs, report_violation: ReportViolation): if args.resource_type == "gcp:compute/firewall:Firewall": allows = args.props["allows"] for rule in allows: for port in rule.get("ports"): if int(port) > 1024: report_violation( f"accessible port number is too big! {port}") compute_firewall_rule = ResourceValidationPolicy( name="compute_firewall_rule", description= "Accessible port number should not be larger than 1024. If necessary, please confirm the security guy to change the policies for this project", validate=compute_firewall_rule_validator, ) PolicyPack( name="intro-policy-check", enforcement_level=EnforcementLevel.MANDATORY, policies=[ compute_instance_located_in_tw, compute_firewall_rule, ], )
assert r.props["fileArchive"].path == "." assert isinstance(r.props["assetArchive"], pulumi.AssetArchive) assets = r.props["assetArchive"].assets assert isinstance(assets["fileAsset"], pulumi.FileAsset) assert assets["fileAsset"].path == "index.ts" assert isinstance(assets["stringAsset"], pulumi.StringAsset) assert assets["stringAsset"].text == "some text" assert isinstance(assets["fileArchive"], pulumi.FileArchive) assert assets["fileArchive"].path == "." PolicyPack( name="deserialize-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ ResourceValidationPolicy( name="resource-validation", description= "Verifies deserialized properties during resource validation.", validate=validate_resource, ), StackValidationPolicy( name="stack-validation", description= "Verifies deserialized properties during stack validation.", validate=validate_stack, ), ], )
PolicyPack( name="validate-resource-test-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ ResourceValidationPolicy( name="dynamic-no-state-with-value-1", description="Prohibits setting state to 1 on dynamic resources.", validate=dynamic_no_state_with_value_1, ), ResourceValidationPolicy( name="dynamic-no-state-with-value-2", description="Prohibits setting state to 2 on dynamic resources.", validate=dynamic_no_state_with_value_2, ), ResourceValidationPolicy( name="dynamic-no-state-with-value-3-or-4", description= "Prohibits setting state to 3 or 4 on dynamic resources.", validate=[ dynamic_no_state_with_value_3, dynamic_no_state_with_value_4, ], ), ResourceValidationPolicy( name="randomuuid-no-keepers", description= "Prohibits creating a RandomUuid without any 'keepers'.", validate=randomuuid_no_keepers, ), ResourceValidationPolicy( name="dynamic-no-state-with-value-5", description="Prohibits setting state to 5 on dynamic resources.", validate=dynamic_no_state_with_value_5, ), ResourceValidationPolicy( name="large-resource", description= "Ensures that large string properties are set properly.", validate=large_resource, ) ], )
def validate_resource(args, report_violation): if validate_function_raises: raise AssertionError("validate-resource should never be called.") report_violation("validate-resource-violation-message") def validate_stack(args, report_violation): if validate_function_raises: raise AssertionError("validate-stack should never be called.") report_violation("validate-stack-violation-message") PolicyPack( name=policy_pack_name, enforcement_level=scenario.pack, policies=[ ResourceValidationPolicy( name="validate-resource", description="Always reports a resource violation.", enforcement_level=scenario.policy, validate=validate_resource, ), StackValidationPolicy( name="validate-stack", description="Always reports a stack violation.", enforcement_level=scenario.policy, validate=validate_stack, ), ], )
PolicyPack( name="validate-stack-test-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ StackValidationPolicy( name="dynamic-no-state-with-value-1", description="Prohibits setting state to 1 on dynamic resources.", validate=dynamic_no_state_with_value_1, ), # More than one policy. StackValidationPolicy( name="dynamic-no-state-with-value-2", description="Prohibits setting state to 2 on dynamic resources.", validate=dynamic_no_state_with_value_2, ), # Policy that specifies the URN of the resource violating the policy. StackValidationPolicy( name="dynamic-no-state-with-value-3", description="Prohibits setting state to 3 on dynamic resources.", validate=dynamic_no_state_with_value_3, ), StackValidationPolicy( name="randomuuid-no-keepers", description= "Prohibits creating a RandomUuid without any 'keepers'.", validate=randomuuid_no_keepers, ), StackValidationPolicy( name="no-randomstrings", description="Prohibits RandomString resources.", validate=no_randomstrings, ), ], )
assert "PULUMI_TEST_STACK" in os.environ assert get_stack() == os.environ["PULUMI_TEST_STACK"] assert get_stack() == r.props["getStack"] # Verify Config assert json.dumps(CONFIG, sort_keys=True) == json.dumps(dict(r.props["allConfig"]), sort_keys=True) config = Config() value = config.require("aConfigValue") assert value == "this value is a value" assert aws_config.region == "us-west-2" PolicyPack( name="runtime-data-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ ResourceValidationPolicy( name="runtime-data-resource-validation", description="Verifies runtime data during resource validation.", validate=validate_resource, ), StackValidationPolicy( name="runtime-data-stack-validation", description="Verifies runtime data during stack validation.", validate=validate_stack, ), ], )
assert r.dependencies[0] is a assert json.dumps(r.property_dependencies) == json.dumps({}) elif t == "random:index/randomString:RandomString": assert r.parent is stack assert json.dumps(r.dependencies) == json.dumps([]) assert json.dumps(r.property_dependencies) == json.dumps({}) elif t == "random:index/randomPet:RandomPet": assert r.parent is stack str_ = next(r for r in resources if r.name == "str") assert len(r.dependencies) == 1 assert r.dependencies[0] is str_ assert "prefix" in r.property_dependencies prefix = r.property_dependencies["prefix"] assert len(prefix) == 1 assert prefix[0] is str_ else: raise AssertionError(f"Unexpected resource of type: '{t}'.") PolicyPack( name="parent-dependencies-test-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ StackValidationPolicy( name="validate-stack", description="Validates resource options during `validateStack`.", validate=validate_stack, ), ], )
ResourceValidationArgs, ResourceValidationPolicy, ) def no_public_services_validator(args: ResourceValidationArgs, report_violation: ReportViolation): if args.resource_type == "kubernetes:core/v1:Service" and "spec" in args.props: spec = args.props["spec"] if "type" in spec and spec["type"] == "LoadBalancer": report_violation( "Kubernetes Services cannot be of type LoadBalancer, which are exposed to " + "anything that can reach the Kubernetes cluster. This likely including the " + "public Internet.") no_public_services = ResourceValidationPolicy( name="no-public-services", description="Kubernetes Services should be cluster-private.", validate=no_public_services_validator, ) PolicyPack( name="kubernetes-python", enforcement_level=EnforcementLevel.MANDATORY, policies=[ no_public_services, ], )
ResourceValidationPolicy, ) def storage_container_no_public_read_validator( args: ResourceValidationArgs, report_violation: ReportViolation): if args.resource_type == "azure:storage/container:Container" and "containerAccessType" in args.props: access_type = args.props["containerAccessType"] if access_type == "blob" or access_type == "container": report_violation( "Azure Storage Container must not have blob or container access set. " + "Read more about read access here: " + "https://docs.microsoft.com/en-us/azure/storage/blobs/storage-manage-access-to-resources" ) storage_container_no_public_read = ResourceValidationPolicy( name="storage-container-no-public-read", description= "Prohibits setting the public permission on Azure Storage Blob Containers.", validate=storage_container_no_public_read_validator, ) PolicyPack( name="azure-python", enforcement_level=EnforcementLevel.MANDATORY, policies=[ storage_container_no_public_read, ], )
verify = check else: raise AssertionError(f"Unexpected test_scenario {test_scenario}.") def validate(args, report_violation): if verify is not None: verify(args.get_config()) PolicyPack( name="config-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ ResourceValidationPolicy( name="resource-validation", description="Verifies policy config during resource validation.", validate=validate, config_schema=schema, ), StackValidationPolicy( name="stack-validation", description="Verifies policy config during stack validation.", validate=validate, config_schema=schema, ), ], initial_config=initial_config, )
return (expected.protect == actual.protect and expected.ignore_changes == actual.ignore_changes and expected.delete_before_replace == actual.delete_before_replace and expected.aliases == actual.aliases and expected.custom_timeouts.create_seconds == actual.custom_timeouts.create_seconds and expected.custom_timeouts.update_seconds == actual.custom_timeouts.update_seconds and expected.custom_timeouts.delete_seconds == actual.custom_timeouts.delete_seconds and expected.additional_secret_outputs == actual.additional_secret_outputs) PolicyPack( name="resource-options-test-policy", enforcement_level=EnforcementLevel.MANDATORY, policies=[ ResourceValidationPolicy( name="validate-resource", description="Validates resource options during `validateResource`.", validate=validate_resource, ), StackValidationPolicy( name="validate-stack", description="Validates resource options during `validateStack`.", validate=validate_stack, ), ], )
for resource in stack.resources: if resource.resource_type == "aws:s3/bucket:Bucket": if "region" in resource.props and resource.props["region"] != required_region: report_violation(f"Bucket, {resource.name}, must be in region {required_region}") s3_region_check = StackValidationPolicy( name="s3-region-check", description= "Checks the region the bucket was deployed in.", validate=s3_region_check_validator ) def s3_count_check_validator(stack: StackValidationArgs, report_violation: ReportViolation): buckets = list(filter((lambda resource: resource.resource_type == "aws:s3/bucket:Bucket"), stack.resources)) if len(buckets) > max_num_buckets: report_violation(f"No more than {max_num_buckets} bucket(s) should be created.") s3_count_check = StackValidationPolicy( name="s3-count-check", description= "Checks the number of buckets created.", validate=s3_count_check_validator ) PolicyPack( name="aws-python", enforcement_level=EnforcementLevel.ADVISORY, policies=[ s3_region_check, s3_count_check ], )