samcli/lib/bootstrap/bootstrap.py (130 lines of code) (raw):
"""
Bootstrap's user's development environment by creating cloud resources required by SAM CLI
"""
import json
import logging
from typing import Optional
import boto3
from botocore.exceptions import ClientError
from samcli import __version__
from samcli.cli.global_config import GlobalConfig
from samcli.commands.exceptions import AWSServiceClientError, UserException
from samcli.lib.utils.managed_cloudformation_stack import StackOutput
from samcli.lib.utils.managed_cloudformation_stack import manage_stack as manage_cloudformation_stack
SAM_CLI_STACK_NAME = "aws-sam-cli-managed-default"
LOG = logging.getLogger(__name__)
def manage_stack(profile, region):
outputs: StackOutput = manage_cloudformation_stack(
profile=None, region=region, stack_name=SAM_CLI_STACK_NAME, template_body=_get_stack_template()
)
bucket_name = outputs.get("SourceBucket")
if bucket_name is None:
msg = (
"Stack " + SAM_CLI_STACK_NAME + " exists, but is missing the managed source bucket key. "
"Failing as this stack was likely not created by the AWS SAM CLI."
)
raise UserException(msg)
# This bucket name is what we would write to a config file
return bucket_name
def get_current_account_id(profile: Optional[str] = None):
"""Returns account ID based on used AWS credentials."""
session = boto3.Session(profile_name=profile)
sts_client = session.client("sts")
try:
caller_identity = sts_client.get_caller_identity()
except ClientError as ex:
if ex.response["Error"]["Code"] == "InvalidClientTokenId":
raise AWSServiceClientError("Cannot identify account due to invalid configured credentials.") from ex
raise AWSServiceClientError("Cannot identify account based on configured credentials.") from ex
if "Account" not in caller_identity:
raise AWSServiceClientError("Cannot identify account based on configured credentials.")
return caller_identity["Account"]
def _get_stack_template():
gc = GlobalConfig()
template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "Managed Stack for AWS SAM CLI",
"Metadata": {
"SamCliInfo": {
"version": __version__,
"installationId": gc.installation_id if gc.installation_id else "unknown",
}
},
"Resources": {
"SamCliSourceBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"PublicAccessBlockConfiguration": {
"BlockPublicPolicy": "true",
"BlockPublicAcls": "true",
"IgnorePublicAcls": "true",
"RestrictPublicBuckets": "true",
},
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{"ServerSideEncryptionByDefault": {"SSEAlgorithm": "aws:kms"}}
]
},
"VersioningConfiguration": {"Status": "Enabled"},
"Tags": [{"Key": "ManagedStackSource", "Value": "AwsSamCli"}],
},
},
"SamCliSourceBucketBucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"Properties": {
"Bucket": {"Ref": "SamCliSourceBucket"},
"PolicyDocument": {
"Statement": [
{
"Action": ["s3:GetObject"],
"Effect": "Allow",
"Resource": {
"Fn::Join": [
"",
[
"arn:",
{"Ref": "AWS::Partition"},
":s3:::",
{"Ref": "SamCliSourceBucket"},
"/*",
],
]
},
"Principal": {"Service": "serverlessrepo.amazonaws.com"},
"Condition": {"StringEquals": {"aws:SourceAccount": {"Ref": "AWS::AccountId"}}},
},
{
"Action": ["s3:*"],
"Effect": "Deny",
"Resource": [
{
"Fn::Join": [
"",
[
"arn:",
{"Ref": "AWS::Partition"},
":s3:::",
{"Ref": "SamCliSourceBucket"},
],
]
},
{
"Fn::Join": [
"",
[
"arn:",
{"Ref": "AWS::Partition"},
":s3:::",
{"Ref": "SamCliSourceBucket"},
"/*",
],
]
},
],
"Principal": "*",
"Condition": {"Bool": {"aws:SecureTransport": "false"}},
},
]
},
},
},
},
"Outputs": {"SourceBucket": {"Value": {"Ref": "SamCliSourceBucket"}}},
}
return json.dumps(template)