Пример #1
0
def test_aws_config_bucket(stack: Stack) -> None:
    """Test AWS Config Bucket creation.

    Note that a bucket policy is also created when a Bucket is instanciated
    """
    stack.add(AWSConfigBucket(name="test-bucket"))
    assert stack.export()["Resources"] == EXPECTED_AWS_CONFIG_BUCKET
Пример #2
0
def test_s3_access_managed_policy(stack: Stack) -> None:
    """Test S3 access managed policy creation."""
    stack.add(
        S3AccessManagedPolicy(
            name="S3ManagedPolicy",
            buckets=["test-bucket"],
            action=["s3:PutObject"],
            roles=["TestRole"],
        )
    )
    assert stack.export()["Resources"] == EXPECTED_S3_ACCESS_MANAGED_POLICY
Пример #3
0
def test_config_rules(stack: Stack) -> None:
    """Test config rules creation."""
    for config_rule in (
            S3BucketPublicWriteProhibited,
            S3BucketPublicReadProhibited,
            S3BucketServerSideEncryptionEnabled,
            S3BucketSSLRequestsOnly,
            IAMUserNoPoliciesCheck,
    ):
        stack.add(config_rule)

    assert stack.export()["Resources"] == EXPECTED_RULES
Пример #4
0
def test_role(stack: Stack) -> None:
    """Test IAM role creation.

    Creating a Role also tests PolicyDocument and Policystatement classes.
    """
    stack.add(
        Role(
            name="TestRole",
            description="TestRole description",
            principal={"Service": "test"},
        )
    )
    assert stack.export()["Resources"] == EXPECTED_ROLE
Пример #5
0
def stack() -> Stack:
    """Stack fixture to help dumping dictionnaries from constructs."""
    return Stack("test-stack", "this is a test stack")
Пример #6
0
def build_and_deploy_tstacks() -> None:
    """Build and deploy two simple troposphere stacks.

    Two stacks in two different regions are deployed. An us stack define only a secure
    bucket. An eu stack define secure s3 buckets, a role to add object to the eu bucket
    and a AWSConfig recorder with rules that check s3 buckets security configurations
    across both regions.
    """
    sessions = {
        "eu": Session(regions=["eu-west-1"]),
        "us": Session(regions=["us-east-1"]),
    }
    stack = {}
    for region in ("eu", "us"):
        stack[region] = Stack(
            f"e3-example-{region}",
            sessions[region],
            opts={"Capabilities": ["CAPABILITY_NAMED_IAM"]},
        )

    # Add a s3 secure bucket in each region
    stack["eu"].add_construct([Bucket(name="e3-l1-example")])
    stack["us"].add_construct([Bucket(name="e3-l2-example")])

    # Define a new IAM-Roles that will be used to acces e3-l1-example bucket
    stack["eu"].add_construct(
        [
            Role(
                name="L1WriteRole",
                description="Role to write to l1 buckets",
                principal={"Service": "ecs-tasks.amazonaws.com"},
            )
        ]
    )

    # Define a new IAM-Policy to putObject in e3-l1-example bucket
    # and attach the L1WriteRole role to it
    stack["eu"].add_construct(
        [
            S3AccessManagedPolicy(
                name="S3WriteAccess",
                buckets=["e3-l1-example"],
                action=["s3:PutObject"],
                roles=[Ref(stack["eu"]["L1WriteRole"])],
            )
        ]
    )

    # Add AWS config rules to check S3 buckets security configuration.
    # This should only be defined in one region
    for region in ("eu",):
        stack[region].add_construct(
            [ConfigurationRecorder(bucket_name="config-bucket-example")]
        )

    for region in ("eu",):
        stack[region].add_construct(
            [
                S3BucketPublicWriteProhibited,
                S3BucketPublicReadProhibited,
                S3BucketServerSideEncryptionEnabled,
                S3BucketSSLRequestsOnly,
                IAMUserNoPoliciesCheck,
            ]
        )

    # Deploy stacks
    for region in ("eu", "us"):
        stack[region].deploy()
Пример #7
0
def test_instanciate() -> None:
    """Test stack instanciation."""
    stack = Stack("test-stack", "this is a test stack")
    assert stack
Пример #8
0
def test_add_and_get_item() -> None:
    """Test adding a construct and retrieving an AWSObject from a stack."""
    stack = Stack("test-stack", "this is a test stack")
    stack.add(Bucket("my-bucket"))
    my_bucket = stack["my-bucket"]
    assert my_bucket
Пример #9
0
def test_config_recorder(stack: Stack) -> None:
    """Test config recorder creation."""
    stack.add(ConfigurationRecorder(bucket_name="config-test-bucket"))
    assert stack.export()["Resources"] == EXPECTED_RECORDER
Пример #10
0
    def execute_for_stack(self, stack: Stack) -> int:
        """Execute application for a given stack and return exit status.

        :param Stack: the stack on which the application executes
        """
        try:
            if self.args.command in ("push", "update"):
                if self.data_dir is not None and self.s3_data_key is not None:
                    s3 = self.aws_env.client("s3")

                    # synchronize data to the bucket before creating the stack
                    for f in find(self.data_dir):
                        with open(f, "rb") as fd:
                            subkey = os.path.relpath(f, self.data_dir).replace(
                                "\\", "/"
                            )
                            logging.info(
                                "Upload %s to %s:%s%s",
                                subkey,
                                self.s3_bucket,
                                self.s3_data_key,
                                subkey,
                            )
                            s3.put_object(
                                Bucket=self.s3_bucket,
                                Body=fd,
                                ServerSideEncryption="AES256",
                                Key=self.s3_data_key + subkey,
                            )

                if self.s3_template_key is not None:
                    logging.info(
                        "Upload template to %s:%s", self.s3_bucket, self.s3_template_key
                    )
                    s3.put_object(
                        Bucket=self.s3_bucket,
                        Body=stack.body.encode("utf-8"),
                        ServerSideEncryption="AES256",
                        Key=self.s3_template_key,
                    )

                logging.info("Validate template for stack %s" % stack.name)
                try:
                    stack.validate(url=self.s3_template_url)
                except Exception:
                    logging.error("Invalid cloud formation template")
                    logging.error(stack.body)
                    raise

                if stack.exists():
                    changeset_name = "changeset%s" % int(time.time())
                    logging.info("Push changeset: %s" % changeset_name)
                    stack.create_change_set(changeset_name, url=self.s3_template_url)
                    result = stack.describe_change_set(changeset_name)
                    while result["Status"] in ("CREATE_PENDING", "CREATE_IN_PROGRESS"):
                        time.sleep(1.0)
                        result = stack.describe_change_set(changeset_name)

                    if result["Status"] == "FAILED":
                        logging.error(result["StatusReason"])
                        stack.delete_change_set(changeset_name)
                        return 1
                    else:
                        for el in result["Changes"]:
                            if "ResourceChange" not in el:
                                continue
                            logging.info(
                                "%-8s %-32s: (replacement:%s)",
                                el["ResourceChange"].get("Action"),
                                el["ResourceChange"].get("LogicalResourceId"),
                                el["ResourceChange"].get("Replacement", "n/a"),
                            )

                        if self.args.apply_changeset:
                            ask = input("Apply change (y/N): ")
                            if ask[0] in "Yy":
                                return stack.execute_change_set(
                                    changeset_name=changeset_name, wait=True
                                )
                        return 0
                else:
                    logging.info("Create new stack")
                    stack.create(url=self.s3_template_url)
                    state = stack.state()
                    if self.args.wait_stack_creation:
                        logging.info("waiting for stack creation...")
                        while "PROGRESS" in state["Stacks"][0]["StackStatus"]:
                            result = stack.resource_status(in_progress_only=False)
                            time.sleep(10.0)
                            state = stack.state()
                        logging.info("done")
            elif self.args.command == "show":
                print(stack.body)
            elif self.args.command == "protect":
                # Enable termination protection
                result = stack.enable_termination_protection()

                if self.stack_policy_body is not None:
                    stack.set_stack_policy(self.stack_policy_body)
                else:
                    print("No stack policy to set")

            return 0
        except botocore.exceptions.ClientError as e:
            logging.error(str(e))
            return 1