def test_create_statements(): """Various statement creations.""" s1 = Deny( apply_to=Principal(PrincipalKind.SERVICE, "myservice"), to="do_something", not_on="resource", ) assert s1.properties s2 = Allow( apply_to=Principal(PrincipalKind.SERVICE, "myservice"), sid="id1", to="do_something", on="allowed_resource", ) assert s2.properties pd1 = PolicyDocument() pd2 = PolicyDocument() pd1.append(s1) pd2.append(s2) pd3 = pd1 + pd2 assert len(pd3.statements) == 2 pd1 += [s2] assert len(pd3.statements) == 2
def add_bucket_access(self, bucket_list): """Authorize access to a list of buckets using vpc endpoint. Note that this just allow an instance in the vpc to ask access to a given bucket through the endpoint. This does not change the bucket policy. The function creates also automatically the S3 VPC endpoint on the first call. :param bucket_list: list of bucket names :type bucket_list: list[Bucket] | list[str] """ if self.name + 'S3EndPoint' not in self: self.add(VPCEndpoint(self.name + 'S3EndPoint', 's3', self.subnet.vpc, [self.route_table], PolicyDocument())) for bucket in bucket_list: if isinstance(bucket, Bucket): bucket_name = bucket.ref else: bucket_name = bucket self.s3_endpoint.policy_document.append( Allow(to='s3:*', on=[Join(['arn:aws:s3:::', bucket_name]), Join(['arn:aws:s3:::', bucket_name, '/*'])], apply_to=Principal(PrincipalKind.EVERYONE)))
def test_create_fortress_no_bastion(): aws_env = AWSEnv(regions=['us-east-1'], stub=True) with default_region('us-east-1'): stub = aws_env.stub('ec2', region='us-east-1') stub.add_response( 'describe_images', { 'Images': [{ 'ImageId': 'ami-1234', 'RootDeviceName': '/dev/sda1', 'Tags': [] }] }, {'ImageIds': ANY}) stub.add_response( 'describe_images', { 'Images': [{ 'ImageId': 'ami-1234', 'RootDeviceName': '/dev/sda1', 'Tags': [] }] }, {'ImageIds': ANY}) d = PolicyDocument().append( Allow(to='s3:GetObject', on=['arn:aws:s3:::mybucket', 'arn:aws:s3:::mybucket/*'])) p = Policy('InternalPolicy', d) f = Fortress('myfortress', bastion_ami=None, internal_server_policy=p) f += Bucket('Bucket2') # Allow access to mybucket through a s3 endpoint f.private_subnet.add_bucket_access(['mybucket', f['Bucket2']]) # allow https f.add_network_access('https') f.add_private_server(AMI('ami-1234'), ['server1', 'server2']) assert f.body
def add_secret_access(self, secret_arn): """Give read access to a given secret. :param secret_name: arn identifying the secret to give access to :type secret_name: str """ endpoint_name = f"{self.name}SecretsManagerEndPoint" if endpoint_name not in self: self.add( VPCInterfaceEndpoint( name=endpoint_name, service="secretsmanager", vpc=self.vpc, subnet=self.aws_endpoints_subnet.subnet, policy_document=PolicyDocument(), security_group=self.aws_endpoints_security_group, )) self.secretsmanager_endpoint.policy_document.append( Allow( to=[ "secretsmanager:GetResourcePolicy", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds", ], on=[secret_arn], apply_to=Principal(PrincipalKind.EVERYONE), ))
def test_create_fortress(enable_github, requests_mock): if enable_github: requests_mock.get("https://api.github.com/meta", json=GITHUB_API_RANGE) requests_mock.get("https://ip-ranges.amazonaws.com/ip-ranges.json", json=AWS_IP_RANGES) aws_env = AWSEnv(regions=["us-east-1"], stub=True) with default_region("us-east-1"): stub = aws_env.stub("ec2", region="us-east-1") stub.add_response( "describe_images", { "Images": [{ "ImageId": "ami-1234", "RootDeviceName": "/dev/sda1", "Tags": [] }] }, {"ImageIds": ANY}, ) stub.add_response( "describe_images", { "Images": [{ "ImageId": "ami-1234", "RootDeviceName": "/dev/sda1", "Tags": [] }] }, {"ImageIds": ANY}, ) d = PolicyDocument().append( Allow( to="s3:GetObject", on=["arn:aws:s3:::mybucket", "arn:aws:s3:::mybucket/*"], )) p = Policy("InternalPolicy", d) f = Fortress( "myfortress", allow_ssh_from="0.0.0.0/0", bastion_ami=AMI("ami-1234"), internal_server_policy=p, ) f += Bucket("Bucket2") # Allow access to mybucket through a s3 endpoint f.private_subnet.add_bucket_access(["mybucket", f["Bucket2"]]) # Allow access to a secret throught a secretsmanager endpoint f.add_secret_access("arn_secret") # Allow access to lambdas throught lambda endpoints f.add_secret_access(["arn_lambda_1", "arn_lambda_2"]) # allow https f.add_network_access("https") f.add_private_server(AMI("ami-1234"), ["server1", "server2"], github_access=enable_github) assert f.body
def test_create_bucket_policy(): p = PolicyDocument().append((Allow(to='s3:GetObject', on=['arn:aws:s3:::mybucket']))) b = BucketPolicy(name='mypolicy', bucket='mybucket', policy_document=p) assert b.properties b = BucketPolicy(name='mypolicy', bucket=Bucket(name='mybucket'), policy_document=p) assert b.properties
def test_create_bucket_policy(): p = PolicyDocument().append((Allow(to="s3:GetObject", on=["arn:aws:s3:::mybucket"]))) b = BucketPolicy(name="mypolicy", bucket="mybucket", policy_document=p) assert b.properties b = BucketPolicy(name="mypolicy", bucket=Bucket(name="mybucket"), policy_document=p) assert b.properties
def test_create_instance_profile(): """Create a basic instance role that get access to a bucket.""" s = Bucket("MyBucket") policy_document = PolicyDocument() policy_document.append(Allow().to( ["s3:ListBucket", "s3:GetObject", "s3:ListObjects"]).on(s.arn)) instance_profile = InstanceRole("InstRole") instance_profile.add_policy(Policy("Pol", policy_document)) assert instance_profile.body
def test_create_instance_profile(): """Create a basic instance role that get access to a bucket.""" s = Bucket('MyBucket') policy_document = PolicyDocument() policy_document.append( Allow().to(['s3:ListBucket', 's3:GetObject', 's3:ListObjects']).on(s.arn)) instance_profile = InstanceRole('InstRole') instance_profile.add_policy(Policy('Pol', policy_document)) assert instance_profile.body
def test_create_fortress_no_bastion(): aws_env = AWSEnv(regions=["us-east-1"], stub=True) with default_region("us-east-1"): stub = aws_env.stub("ec2", region="us-east-1") stub.add_response( "describe_images", { "Images": [{ "ImageId": "ami-1234", "RootDeviceName": "/dev/sda1", "Tags": [] }] }, {"ImageIds": ANY}, ) stub.add_response( "describe_images", { "Images": [{ "ImageId": "ami-1234", "RootDeviceName": "/dev/sda1", "Tags": [] }] }, {"ImageIds": ANY}, ) d = PolicyDocument().append( Allow( to="s3:GetObject", on=["arn:aws:s3:::mybucket", "arn:aws:s3:::mybucket/*"], )) p = Policy("InternalPolicy", d) f = Fortress("myfortress", bastion_ami=None, internal_server_policy=p) f += Bucket("Bucket2") # Allow access to mybucket through a s3 endpoint f.private_subnet.add_bucket_access(["mybucket", f["Bucket2"]]) # Allow access to a secret throught a secretsmanager endpoint f.add_secret_access("arn_secret") # allow https f.add_network_access("https") f.add_private_server(AMI("ami-1234"), ["server1", "server2"]) assert f.body
def test_create_network(): s = Stack(name="teststack") s = Stack(name="MyStack") s += VPC("BuildVPC", "10.10.0.0/16") s += InternetGateway("Gate") s += Subnet("BuildPublicSubnet", s["BuildVPC"], "10.10.10.0/24") s += Subnet("BuildPrivateSubnet", s["BuildVPC"], "10.10.20.0/24") s += VPCGatewayAttachment("GateAttach", s["BuildVPC"], s["Gate"]) s += RouteTable("RT", s["BuildVPC"]) s += Route("PRoute", s["RT"], "0.0.0.0/0", s["Gate"], s["GateAttach"]) s += SubnetRouteTableAssociation("RTSAssoc", s["BuildPublicSubnet"], s["RT"]) p = PolicyDocument().append( Allow( to="GetObject", on="arn:aws:s3:::abucket/*", apply_to=Principal(PrincipalKind.SERVICE, "ec2.amazonaws.com"), ) ) s += VPCEndpoint("S3EndPoint", "s3", s["BuildVPC"], [s["RT"]], policy_document=p) assert s.body
def test_create_network(): s = Stack(name='teststack') s = Stack(name='MyStack') s += VPC('BuildVPC', '10.10.0.0/16') s += InternetGateway('Gate') s += Subnet('BuildPublicSubnet', s['BuildVPC'], '10.10.10.0/24') s += Subnet('BuildPrivateSubnet', s['BuildVPC'], '10.10.20.0/24') s += VPCGatewayAttachment('GateAttach', s['BuildVPC'], s['Gate']) s += RouteTable('RT', s['BuildVPC']) s += Route('PRoute', s['RT'], '0.0.0.0/0', s['Gate'], s['GateAttach']) s += SubnetRouteTableAssociation('RTSAssoc', s['BuildPublicSubnet'], s['RT']) p = PolicyDocument().append( Allow(to='GetObject', on='arn:aws:s3:::abucket/*', apply_to=Principal(PrincipalKind.SERVICE, 'ec2.amazonaws.com'))) s += VPCEndpoint('S3EndPoint', 's3', s['BuildVPC'], [s['RT']], policy_document=p) assert s.body
def test_create_fortress_with_too_much_sgs(): aws_env = AWSEnv(regions=["us-east-1"], stub=True) with default_region("us-east-1"): stub = aws_env.stub("ec2", region="us-east-1") stub.add_response( "describe_images", { "Images": [{ "ImageId": "ami-1234", "RootDeviceName": "/dev/sda1", "Tags": [] }] }, {"ImageIds": ANY}, ) d = PolicyDocument().append( Allow( to="s3:GetObject", on=["arn:aws:s3:::mybucket", "arn:aws:s3:::mybucket/*"], )) p = Policy("InternalPolicy", d) f = Fortress("myfortress", bastion_ami=None, internal_server_policy=p) # Adding 16 extra security groups should raise an exception (The maximum # number of security groups is 16 and there is a default InternalSG) sg_groups = [ SecurityGroup(name=f"sg{id}", vpc=f.vpc.vpc) for id in range(16) ] with pytest.raises(AWSFortressError): f.add_private_server( AMI("ami-1234"), ["server1"], amazon_access=False, github_access=False, extra_groups=sg_groups, )
def add_lambda_access(self, lambda_arns): """Add a lambda interface endpoint with permissions to invoke given lambdas. :param lambda_arns: arn identifying the lambda to give access to :type lambda_arns: list[str] """ endpoint_name = f"{self.name}LambdaEndPoint" if endpoint_name not in self: self.add( VPCInterfaceEndpoint( name=endpoint_name, service="lambda", vpc=self.vpc, subnet=self.aws_endpoints_subnet.subnet, policy_document=PolicyDocument(), security_group=self.aws_endpoints_security_group, )) self.lambda_endpoint.policy_document.append( Allow( to=["lambda:InvokeFunction"], on=chain.from_iterable(((lambda_arn, lambda_arn + ":*") for lambda_arn in lambda_arns)), apply_to=Principal(PrincipalKind.EVERYONE), ))