Monday 20 May 2019

Create STS connection using Boto3

This is not production ready code. It is just as a sample.

import boto3
from boto3 import Session

def connect_sts(region, role_arn):
  sts_client = boto3.client('sts')
 
  session = Session(region_name=region)

  assumedRoleObject = sts_client.assume_role(
    RoleArn=role_arn,
    RoleSessionName="AssumeRoleSession1"
  )

  credentials = assumedRoleObject['Credentials']
  connector = {
    'cloudformation' : session.resource('cloudformation', aws_access_key_id = credentials['AccessKeyId'], aws_secret_access_key = credentials['SecretAccessKey'], aws_session_token = credentials['SessionToken']),
    'iam' : session.resource('iam', aws_access_key_id = credentials['AccessKeyId'], aws_secret_access_key = credentials['SecretAccessKey'], aws_session_token = credentials['SessionToken']),
    'ec2' : session.resource('ec2', aws_access_key_id = credentials['AccessKeyId'], aws_secret_access_key = credentials['SecretAccessKey'], aws_session_token = credentials['SessionToken']),
    's3' : session.resource('s3', aws_access_key_id = credentials['AccessKeyId'], aws_secret_access_key = credentials['SecretAccessKey'], aws_session_token = credentials['SessionToken'])

  }
  #print connector
  return connector

ec22 = connect_sts('eu-west-1','arn:aws:iam::837274771294:role/Administrator')
for vpc in ec22['ec2'].vpcs.all():
  print vpc

Create Basic Infrastructure CloudFormation template using troposphere

Here step by a step python code to create basic infra 
This is not production ready code. It is just as a sample.

________
Infra.py

from troposphere import GetAtt, Ref, Tags, Template, Join
from troposphere import GetAtt, Ref, Tags, Template, Join
from troposphere.ec2 import (Route, VPCGatewayAttachment, SubnetRouteTableAssociation, Subnet, RouteTable, VPC as Vpc,
                             InternetGateway, EIP, NatGateway, VPCEndpoint, VPNGateway, DHCPOptions,
                             VPCDHCPOptionsAssociation, VPNGatewayRoutePropagation, VPCPeeringConnection)

from libs.general import connect, validate_template, push_cloudformation


class ActiveVpcV3(object):
    def __init__(self):
        self.template = Template()
        self.template.add_description('Third instance of Active VPC')
        self.cost_allocation_tag = 'Base infrastructure'

    def resource_title(self, name):
        camel_case_name = name.title().replace("_", "").replace("-", "")
        return camel_case_name

    def create_vpc(self, ip_range):
        VPC = self.template.add_resource(
            Vpc(
                'VPC',
                CidrBlock=ip_range,
                EnableDnsHostnames=True,
                EnableDnsSupport=True,
                Tags=Tags(
                    cost_allocation=self.cost_allocation_tag,
                )
            ))
        return VPC

    def create_s3_endpoint(self, vpc, routes_tables_list):
        self.template.add_resource(VPCEndpoint(
            "S3VpcEndpoint",
            RouteTableIds=routes_tables_list,
            ServiceName=Join("", ["com.amazonaws.", Ref("AWS::Region"), ".s3"]),
            VpcId=vpc,
        ))

    def create_vpn_gateway(self, vpc, routes_tables_list):
        vpn_gateway = self.template.add_resource(VPNGateway(
            'VPNGateway',
            Type='ipsec.1',
            Tags=Tags(
                cost_allocation=self.cost_allocation_tag,
            )
        ))

        self.template.add_resource(VPCGatewayAttachment(
            'VPNGatewayAttachment',
            VpcId=vpc,
            VpnGatewayId=Ref(vpn_gateway),
        ))

        self.template.add_resource(VPNGatewayRoutePropagation(
            'VPNGatewayRoutePropagation',
            RouteTableIds=routes_tables_list,
            VpnGatewayId=Ref(vpn_gateway),
            DependsOn='VPNGatewayAttachment'
        ))

    def create_dhcp_options(self, vpc, domain, dns_server):
        dhcp_options = self.template.add_resource(DHCPOptions(
            'DHCPOptions',
            DomainName=domain,
            DomainNameServers=dns_server
        ))

        self.template.add_resource(VPCDHCPOptionsAssociation(
            'VPCDHCPOptionsAssociation',
            DhcpOptionsId=Ref(dhcp_options),
            VpcId=vpc
        ))

    def create_internet_gateway(self, vpc):
        internet_gateway = self.template.add_resource(
            InternetGateway(
                'InternetGateway',
                Tags=Tags(
                    cost_allocation=self.cost_allocation_tag)))

        self.template.add_resource(
            VPCGatewayAttachment(
                'InternetGatewayAttachment',
                VpcId=vpc,
                InternetGatewayId=Ref(internet_gateway)
            ))

        route_table = self.template.add_resource(RouteTable(
            'PublicRouteRouteTable',
            VpcId=vpc,
            Tags=Tags(
                cost_allocation=self.cost_allocation_tag)
        ))

        self.template.add_resource(Route(
            'PublicRoute',
            RouteTableId=Ref(route_table),
            DestinationCidrBlock='0.0.0.0/0',
            GatewayId=Ref(internet_gateway)
        ))

        return route_table

    def create_nat_gateway(self, name, subnet):
        elastic_ip = self.template.add_resource(EIP(
            "%sEIP" % (self.resource_title(name)),
            Domain="VPC",
        ))

        nat_gateway = self.template.add_resource(NatGateway(
            '%sNatGateway' % (self.resource_title(name)),
            AllocationId=GetAtt(elastic_ip, 'AllocationId'),
            SubnetId=subnet,
        ))
        return nat_gateway

    def create_public_subnet(self, name, vpc, region, ip_range, route_table):
        subnet = self.template.add_resource(
            Subnet(
                '%sSubnet' % self.resource_title(name),
                CidrBlock=ip_range,
                AvailabilityZone=region,
                VpcId=vpc,
                MapPublicIpOnLaunch=True,
                Tags=Tags(
                    cost_allocation=self.cost_allocation_tag,
                )
            ))

        self.template.add_resource(SubnetRouteTableAssociation(
            '%sRouteTableAssociation' % self.resource_title(name),
            SubnetId=Ref(subnet),
            RouteTableId=route_table,

        ))
        return subnet

    def create_private_subnet(self, name, vpc, ip_range, region, nat_gw):
        subnet = self.template.add_resource(
            Subnet(
                '%sSubnet' % self.resource_title(name),
                CidrBlock=ip_range,
                AvailabilityZone=region,
                VpcId=vpc,
                MapPublicIpOnLaunch=False,
                Tags=Tags(
                    cost_allocation=self.cost_allocation_tag,
                )
            ))

        route_table = self.template.add_resource(RouteTable(
            '%sRouteTable' % self.resource_title(name),
            VpcId=vpc,
            Tags=Tags(
                cost_allocation=self.cost_allocation_tag)
        ))

        self.template.add_resource(SubnetRouteTableAssociation(
            '%sRouteTableAssociation' % self.resource_title(name),
            SubnetId=Ref(subnet),
            RouteTableId=Ref(route_table),

        ))

        self.template.add_resource(Route(
            '%sNatRoute' % self.resource_title(name),
            RouteTableId=Ref(route_table),
            DestinationCidrBlock='0.0.0.0/0',
            NatGatewayId=nat_gw,
        ))

        return dict(subnet=subnet, route_table=route_table)

    def create_vpc_peering(self, name, local_vpc, remote_vpc):
        peering = self.template.add_resource(VPCPeeringConnection(
            '%sPeering' % self.resource_title(name),
            PeerVpcId=Ref(local_vpc),
            VpcId=remote_vpc,
        ))

        return peering

    def create_route_peering(self, name, destination_cidr, vpc_peering, route_table):
        self.template.add_resource(Route(
            '%sPeeringRoute' % self.resource_title(name),
            DestinationCidrBlock=destination_cidr,
            RouteTableId=route_table,
            VpcPeeringConnectionId=vpc_peering
        ))

v = ActiveVpcV3()
vpc = v.create_vpc('192.168.208.0/20')
v.create_dhcp_options(vpc=Ref(vpc),
                      domain='ec2.internal',
                      dns_server=['192.168.210.15', '192.168.215.225']
                      # DomainName='ec2.internal',
                      # DomainNameServers=['AmazonProvidedDNS']
                      )
default_igw_route = v.create_internet_gateway(vpc=Ref(vpc))

pub_subnet_a = v.create_public_subnet(name='general_public_a',
                                      ip_range='192.168.216.0/24',
                                      route_table=Ref(default_igw_route),
                                      region='us-east-1a',
                                      vpc=Ref(vpc))

pub_subnet_b = v.create_public_subnet(name='general_public_b',
                                      ip_range='192.168.217.0/24',
                                      route_table=Ref(default_igw_route),
                                      region='us-east-1b',
                                      vpc=Ref(vpc))

nat_gw_a = v.create_nat_gateway(name='nat_a', subnet=Ref(pub_subnet_a))
nat_gw_b = v.create_nat_gateway(name='nat_b', subnet=Ref(pub_subnet_b))

priv_subnet_a = v.create_private_subnet(name='general_private_1a',
                                        vpc=Ref(vpc),
                                        ip_range='192.168.208.0/22',
                                        region='us-east-1a',
                                        nat_gw=Ref(nat_gw_a))

priv_subnet_b = v.create_private_subnet(name='general_private_1b',
                                        vpc=Ref(vpc),
                                        ip_range='192.168.212.0/22',
                                        region='us-east-1b',
                                        nat_gw=Ref(nat_gw_b))

jenkins_dev_subnet = v.create_private_subnet(name='jenkins_dev_subnet1b',
                                             vpc=Ref(vpc),
                                             ip_range='192.168.218.0/26',
                                             region='us-east-1b',
                                             nat_gw=Ref(nat_gw_b))

jenkins_prod_subnet = v.create_private_subnet(name='jenkins_prod_subnet1b',
                                              vpc=Ref(vpc),
                                              ip_range='192.168.218.64/26',
                                              region='us-east-1b',
                                              nat_gw=Ref(nat_gw_b))

s3_proxy_subnet = v.create_private_subnet(name='s3_proxy_subnet',
                                          vpc=Ref(vpc),
                                          ip_range='192.168.223.224/27',
                                          region='us-east-1b',
                                          nat_gw=Ref(nat_gw_b))

v.create_vpn_gateway(vpc=Ref(vpc),
                     routes_tables_list=[Ref(priv_subnet_a['route_table']),
                                         Ref(priv_subnet_b['route_table']),
                                         Ref(jenkins_dev_subnet['route_table']),
                                         Ref(jenkins_prod_subnet['route_table']),
                                         Ref(s3_proxy_subnet['route_table'])]
                     )

v.create_s3_endpoint(vpc=Ref(vpc),
                     routes_tables_list=[Ref(default_igw_route),
                                         Ref(priv_subnet_a['route_table']),
                                         Ref(priv_subnet_b['route_table']),
                                         Ref(jenkins_dev_subnet['route_table']),
                                         Ref(jenkins_prod_subnet['route_table']),
                                         Ref(s3_proxy_subnet['route_table'])]
                     )

peer01 = v.create_vpc_peering(name='Active_v3_to_Active_v2', local_vpc=vpc, remote_vpc='vpc-833793e6')

v.create_route_peering(name='Active_v3_priv_subnet_a',
                       destination_cidr='192.168.0.0/22',
                       route_table=Ref(priv_subnet_a['route_table']),
                       vpc_peering=Ref(peer01))

v.create_route_peering(name='Active_v3_priv_subnet_b',
                       destination_cidr='192.168.0.0/22',
                       route_table=Ref(priv_subnet_b['route_table']),
                       vpc_peering=Ref(peer01))

v.create_route_peering(name='Active_v2_priv_subnet_a',
                       destination_cidr=GetAtt(vpc, 'CidrBlock'),
                       route_table='rtb-337cd956',
                       vpc_peering=Ref(peer01))


template = v.template.to_json(indent=None)
client = connect('us-east-1')
validate_template(client, template)

push_cloudformation(client, template, 'VPC-Activev3')


Create CloudFormation template using troposphere

Here step by a step python code to create IAM role.
This is not production ready code. It is just as a sample.


CreateRole.py

from awacs.aws import Allow, Deny, Statement, Principal, Policy, Action
from troposphere import Template, Ref, GetAtt, Output
from troposphere.iam import Role, PolicyType
from awacs.sts import AssumeRole
from libs.common import *


class CfTemplate(object):
    template = Template()

    @classmethod
    def resource_title(cls, name):
        camel_case_name = name.title().replace("_", "").replace("-", "")
        return camel_case_name


class Security(CfTemplate):
    @classmethod
    def create_admin_role(cls, name):
        admin_role = CfTemplate.template.add_resource(Role(
            "%sRole" % CfTemplate.resource_title(name),
            AssumeRolePolicyDocument=Policy(
                Statement=[
                    Statement(Effect=Allow,
                              Principal=Principal("Service", ["ec2.amazonaws.com"]),
                              Action=[AssumeRole], )
                ]
            ),
            ManagedPolicyArns=[
                "arn:aws:iam::aws:policy/AdministratorAccess"
            ]
        ))

        CfTemplate.template.add_output(
            Output(
                "%sOutput" % cls.resource_title(name),
                Description="RoleArn",
                Value=GetAtt(admin_role, "Arn")
            )
        )

        return admin_role

    @classmethod
    def create_developer_role(cls, name):
        dev_role = CfTemplate.template.add_resource(Role(
            "%sRole" % CfTemplate.resource_title(name),
            AssumeRolePolicyDocument=Policy(
                Statement=[
                    Statement(Effect=Allow,
                              Principal=Principal("Service", ["ec2.amazonaws.com"]),
                              Action=[AssumeRole], )
                ]
            ),
            ManagedPolicyArns=[
                "arn:aws:iam::aws:policy/AWSElasticBeanstalkFullAccess",
                "arn:aws:iam::aws:policy/AmazonElasticMapReduceFullAccess",
                "arn:aws:iam::aws:policy/service-role/AWSDataPipelineRole"
            ]
        ))

        CfTemplate.template.add_output(
            Output(
                "%sOutput" % cls.resource_title(name),
                Description="RoleArn",
                Value=GetAtt(dev_role, "Arn")
            )
        )

        return dev_role

    @classmethod
    def create_developer_policy(cls, developer_role):
        developer_policy = CfTemplate.template.add_resource(PolicyType(
            "DeveloperPolicy",
            PolicyName="DeveloperPolicy",
            Roles=[Ref(developer_role)],
            PolicyDocument=Policy(
                Statement=[
                    Statement(
                        Effect=Deny,
                        Action=[
                            # VPCs
                            Action("ec2", "CreateVpc"),
                            Action("ec2", "ModifyVpcAttribute"),
                            Action("ec2", "DeleteVpc"),
                            # VPC endpoints
                            Action("ec2", "CreateVpcEndpoint"),
                            Action("ec2", "ModifyVpcEndpoint"),
                            Action("ec2", "DeleteVpcEndpoints"),
                            # VPC classic
                            Action("ec2", "AttachClassicLinkVpc"),
                            Action("ec2", "DetachClassicLinkVpc"),
                            Action("ec2", "EnableVpcClassicLink"),
                            Action("ec2", "DisableVpcClassicLink"),
                            Action("ec2", "EnableVpcClassicLinkDnsSupport"),
                            Action("ec2", "DisableVpcClassicLinkDnsSupport"),
                            # VPC peerings
                            Action("ec2", "CreateVpcPeeringConnection"),
                            Action("ec2", "ModifyVpcPeeringConnectionOptions"),
                            Action("ec2", "RejectVpcPeeringConnection"),
                            Action("ec2", "DeleteVpcPeeringConnection"),
                            # Subnets
                            Action("ec2", "CreateSubnet"),
                            Action("ec2", "DeleteSubnet"),
                            Action("ec2", "ModifySubnetAttribute"),
                            # Route Tables
                            Action("ec2", "AssociateRouteTable"),
                            Action("ec2", "ReplaceRouteTableAssociation"),
                            Action("ec2", "DisassociateRouteTable"),
                            # Routes
                            Action("ec2", "CreateRoute"),
                            Action("ec2", "ReplaceRoute"),
                            Action("ec2", "DeleteRoute"),
                            Action("ec2", "CreateRouteTable"),
                            Action("ec2", "DeleteRouteTable"),
                            # VPN routing
                            Action("ec2", "CreateVpnConnectionRoute"),
                            Action("ec2", "DeleteVpnConnectionRoute"),
                            Action("ec2", "EnableVgwRoutePropagation"),
                            Action("ec2", "DisableVgwRoutePropagation"),
                            # Customer Gateways
                            Action("ec2", "CreateCustomerGateway"),
                            Action("ec2", "DeleteCustomerGateway"),
                            # VPN Gateways
                            Action("ec2", "CreateVpnGateway"),
                            Action("ec2", "DeleteVpnGateway"),
                            Action("ec2", "CreateVpnConnection"),
                            Action("ec2", "DeleteVpnConnection"),
                            Action("ec2", "CreateVpnConnectionRoute"),
                            Action("ec2", "DeleteVpnConnectionRoute"),
                            Action("ec2", "AttachVpnGateway"),
                            Action("ec2", "DetachVpnGateway"),
                            # Network ACLs
                            Action("ec2", "CreateNetworkAcl"),
                            Action("ec2", "DeleteNetworkAcl"),
                            Action("ec2", "CreateNetworkAclEntry"),
                            Action("ec2", "ReplaceNetworkAclEntry"),
                            Action("ec2", "DeleteNetworkAclEntry"),
                            Action("ec2", "ReplaceNetworkAclAssociation"),
                            # Reserved, scheduled and dedicated instances
                            Action("ec2", "CancelReservedInstancesListing"),
                            Action("ec2", "ModifyReservedInstances"),
                            Action("ec2", "PurchaseReservedInstancesOffering"),
                            Action("ec2", "PurchaseHostReservation"),
                            Action("ec2", "PurchaseScheduledInstances"),
                        ],
                        Resource=["*"]
                    ),
                    Statement(
                        Effect=Deny,
                        Action=[
                            Action("*"),
                        ],
                        Resource=[
                            GetAtt(developer_role, "Arn"),
                            "arn:aws:cloudformation:::stack/BaseInfrastructure*",
                        ],
                    ),
                    Statement(
                        Effect=Allow,
                        Action=[
                            Action("support", "*"),
                            Action("ec2", "*"),
                            Action("ecs", "*"),
                            Action("ecr", "*"),
                            Action("lambda", "*"),
                            Action("elasticbeanstalk", "*"),
                            Action("s3", "*"),
                            Action("glacier", "*"),
                            Action("rds", "*"),
                            Action("dynamodb", "*"),
                            Action("elasticache", "*"),
                            Action("redshift", "*"),
                            Action("route53", "*"),
                            Action("cloudwatch", "*"),
                            Action("events", "*"),
                            Action("logs", "*"),
                            Action("cloudformation", "*"),
                            Action("elasticmapreduce", "*"),
                            Action("datapipeline", "*"),
                            Action("es", "*"),
                            Action("kinesis", "*"),
                            Action("kinesisanalytics", "*"),
                            Action("firehose", "*"),
                            Action("sns", "*"),
                            Action("sqs", "*"),
                            Action("apigateway", "*"),
                            Action("autoscaling", "*"),
                            Action("application-autoscaling", "*")
                        ],
                        Resource=["*"],
                    )
                ],
            )
        ))

admin = Security.create_admin_role("administrator")
dev = Security.create_developer_role("developer")
Security.create_developer_policy(dev)

t = CfTemplate.template.to_json(indent=None)
client = connect('us-east-1')
validate_template(client, t)


__________

You have to create common python file which create CF

common.py

from StringIO import StringIO
from base64 import b64encode
from datetime import datetime
from gzip import GzipFile
from pprint import pprint
from shutil import copyfileobj
from time import time, mktime
from uuid import uuid4

import botocore
from boto3 import Session
from troposphere.ec2 import SecurityGroupRule


def connect(region):
    session = Session(region_name=region)
    connectors = {
        'cloudformation': session.client('cloudformation'),
        'iam': session.client('iam'),
        'ec2': session.client('ec2'),
        's3': session.client('s3')
    }
    return connectors


def validate_template(aws, template):
    response = aws['cloudformation'].validate_template(
        TemplateBody=template
    )
    pprint(response)


def push_cloudformation(aws, template, stack_name, parameters_list=list()):
    def create_stack_change(aws, template, stack_name, parameters_list):
        response = aws['cloudformation'].create_change_set(
            StackName=stack_name,
            TemplateBody=template,
            ChangeSetName='changeset%s' % (datetime.fromtimestamp(time()).strftime('%Y%m%d%H%M%S')),
            Description=str(uuid4()),
            Capabilities=[
                'CAPABILITY_IAM',
            ],
            Parameters=parameters_list
        )
        pprint(response)

    def create_stack(aws, template, stack_name, parameters_list):
        response = aws['cloudformation'].create_stack(
            StackName=stack_name,
            TemplateBody=template,
            Capabilities=[
                'CAPABILITY_IAM',
            ],
            OnFailure='DO_NOTHING',
            Parameters=parameters_list
        )
        pprint(response)

    def lookup_stack(aws, stackname, ):
        try:
            response = aws['cloudformation'].describe_stacks(
                StackName=stackname,
            )
            for stack in response.get('Stacks'):
                if "PROGRESS" in stack.get('StackStatus'):
                    raise SystemExit("Stack update in progress")
                elif "FAILED" in stack.get('StackStatus'):
                    raise SystemExit("Stack in failed status")
                else:
                    return ("stack_ready")

        except botocore.exceptions.ClientError as e:
            if e.response['Error']['Code'] == 'ValidationError':
                return ("non_existing_stack")

    status = lookup_stack(aws, stack_name)
    if status is "non_existing_stack":
        print("Creating new stack...")
        create_stack(aws, template, stack_name, parameters_list)
    elif status is "stack_ready":
        print("Creating change set...")
        create_stack_change(aws, template, stack_name, parameters_list)


def generate_sg_rules(protocol, low_port, high_port, acl_ips):
    acl = []
    for ip in acl_ips:
        acl.append(SecurityGroupRule(
            IpProtocol=protocol,
            FromPort=low_port,
            ToPort=high_port,
            CidrIp=ip,
        ))
    return acl


def get_data_from_stack(region, stack_name, key):
    client = connect(region)
    response = client['cloudformation'].describe_stacks(
        StackName=stack_name,
    )
    for i in response.get('Stacks'):
        for j in i.get('Outputs'):
            if j.get('OutputKey') == key:
                return j.get('OutputValue')


def prepare_ansible_playbook(file_path):
    magicdate = datetime(2016, 1, 1, 2, 15)
    gz = StringIO()
    with open(file_path, 'rb') as f_in, GzipFile(fileobj=gz, mode="wb", mtime=mktime(magicdate.timetuple())) as f_out:
        copyfileobj(f_in, f_out)

    gz.seek(0)
    gz_b64 = b64encode(gz.read())



    return gz_b64