21

We have some security groups that have quite a few rules in them. Rather than having to recreate the same rules for a number of security groups just to accommodate minor differences, is it possible to copy a security group to use as a starting point, or use inheritance, etc?

Bill Rosmus
  • 369
  • 1
  • 2
  • 11
  • 2
    You can apply multiple security groups to a single resource. Making a copy of a security group seems like a bad idea. Just add the new rules to a new group and apply it to the right instances. – Ladadadada May 23 '13 at 06:51
  • I just tried searching for this info but cant find anything that shows how to add additional security groups to a singe EC2 instance. Can you provide a link? – Bill Rosmus May 23 '13 at 21:07
  • I just wrote a new function in a Python Boto class library I slowly add to. A PITA I shouldn't have had to deal with (as are a lot of things) but at least now I have a simpler and more straight forward interface to do this than anything else I've seen. – Bill Rosmus Aug 22 '13 at 17:02

10 Answers10

18

Doesn't look like you can copy security groups from the web interface. You can however use the AWS CLI to create security groups:

Command :

$ aws ec2 describe-security-groups --group-id MySecurityGroupID

Output :

{
    "securityGroupInfo": [
        {
            "ipPermissionsEgress": [],
            "groupId": "sg-903004f8",
            "ipPermissions": [],
            "groupName": "MySecurityGroup",
            "ownerId": "803981987763",
            "groupDescription": "AWS-CLI-Example"
        }
    ],
    "requestId": "afb680df-d7b1-4f6a-b1a7-344fdb1e3532"
}

And add rules using command :

aws ec2 authorize-security-group-ingress --group-id MySecurityGroupID --ip-protocol tcp --from-port 22 --to-port 22 --cidr-ip 0.0.0.0/0

Output:

{
    "return": "true",
    "requestId": "c24a1c93-150b-4a0a-b56b-b149c0e660d2"
}

From there you should be able to figure out how to simplify the creation of your security groups.

rtf
  • 884
  • 2
  • 17
  • 31
  • yeah I figured this was the route that would need to be taken... was thinking about doing something similar to this using boto too. Thanks for the example... will give you the thumbs up for it. Thanks. – Bill Rosmus May 23 '13 at 00:12
  • 1
    You must specify the region btw. e.g. `aws ec2 describe-security-groups --group-id MySecurityGroupID --region us-west-2` – evan.bovie Aug 15 '19 at 22:38
8

AWS EC2 Console allows you to select the Security Group and perform the operation "Copy to new" in the UI now.

Luis
  • 81
  • 1
  • 1
4

Here is the 'copy security groups' python/boto method from a custom library I wrote to make these kinds of things easier / automate them.. Ultimately this was the solution I came up with.

vpcId is the Virtual Private Cloud Id
keys is a dictionary with your AWS keys

The rest should be straight forward to figure out.

def copyEC2SecurityGroup(self, keys, region, securityGroupName, newSecurityGroupName = None, newRegion = None, vpcId = None):


newEc2Connection = None
print("Creating ec2Connection for source region: " + region)
ec2Connection = lib.getEc2Connection(region, keys)

if newRegion is None:
    newRegion = region
else:
    print("New Region Detected, creating for New region: " + newRegion)
    newEc2Connection = lib.getEc2Connection(newRegion, keys)
    newRegionInfo = newEc2Connection.region

print("new region is: %s" % newRegion)

if newSecurityGroupName is None:
    newSecurityGroupName = securityGroupName

print ("new security group is: %s" % newSecurityGroupName)

# if copying in the same region the new security group cannot have the same name.
if newRegion == region:
    if newSecurityGroupName == securityGroupName:
        print ("Old and new security groups cannot have the same name when copying to the same region.")
        exit(1)

groups = [group for group in ec2Connection.get_all_security_groups() if group.name == securityGroupName]
print"got groups count " + str(len(groups))
if groups:
    theOldGroup = groups[0]
    print theOldGroup.rules
else:
    print("Can't find security group by the name of: %s" % securityGroupName)
    exit(1)
print groups
pprint(theOldGroup)

if newEc2Connection is not None:
    print("Creating new security group in new region")
    sg = newEc2Connection.create_security_group(newSecurityGroupName, newSecurityGroupName, vpcId)
    sleep(5)
else:
    print("Creating new security group in current region")
    sg = ec2Connection.create_security_group(newSecurityGroupName, newSecurityGroupName, vpcId)
    sleep(5)

source_groups = []
for rule in theOldGroup.rules:
    for grant in rule.grants:
        strGrant = str(grant)
        print(strGrant)
        if strGrant.startswith("sg"):
            print("Cannot copy 'security group rule' (%s)... only cidr_ip's e.g. xxx.xxx.xxx.xxx/yy." % strGrant)
            continue
        grant_nom = grant.name or grant.group_id
        if grant_nom:
            if grant_nom not in source_groups:
                source_groups.append(grant_nom)
                sg.authorize(rule.ip_protocol, rule.from_port, rule.to_port, grant)
        else:
            sg.authorize(rule.ip_protocol, rule.from_port, rule.to_port, grant.cidr_ip)
return sg 
Bill Rosmus
  • 369
  • 1
  • 2
  • 11
  • The code indenting looks out of whack. Can you fix that? – Shoan Aug 22 '15 at 01:13
  • @Shoan - Sorry been too long. I'm not actually working with this right now. This is a method I cut from a library I wrote, and I used it regularly when I was using it. So I know it worked at the time I posted it here. If it is an indent thing, then it shouldn't be too hard to figure it out (but I don't have time right now to build out an environment to fiddle with it, but you can ;) ). It could also be an issue with the version of the library maybe? In any case, it still is likely a good starting point for anyone wanting to do this programmatically with Boto. – Bill Rosmus Aug 31 '15 at 18:23
  • 1
    what is lib? where should I import it from? – Suncatcher Jul 31 '17 at 08:51
4

From AWS Creating a Security Group docs, you can copy a security group using the console.

  1. Select the security group you want to copy
  2. Choose Action
  3. Copy to new

AWS Security Group - Copy to New

Mike D
  • 837
  • 8
  • 10
3

Consider having a look at this blog. It might be useful for what you are looking at.

http://ry4an.org/unblog/post/ec2_security_group_tools/

Sri
  • 31
  • 1
2

Here is the script I made to accomplish this: aws_sg_migrate

Sample usage is

python3 aws_sg_migrate.py --vpc=vpc-05643b6c --shell --src=us-east-1 --dest=us-west-1 sg-111111

It is based on this one and adapted for Python3.

Suncatcher
  • 594
  • 2
  • 7
  • 22
1

Within the same AWS region, you can copy a security policy using the online GUI. However, sometimes you want to copy things programmatically. For instance, if you have a lot of security policies to copy or if you want to copy across regions.

Here's a simple snippet to do that.

import boto3
from os import environ as env


def copy_security_groups(src_region, tgt_region, grp_names):

    # Initialize client connections for regions
    src_client = boto3.client('ec2', region_name=src_region,
                              aws_access_key_id=env['AWS_ACCESS_KEY_ID'],
                              aws_secret_access_key=env['AWS_SECRET_ACCESS_KEY'])
    tgt_client = boto3.client('ec2', region_name=tgt_region,
                              aws_access_key_id=env['AWS_ACCESS_KEY_ID'],
                              aws_secret_access_key=env['AWS_SECRET_ACCESS_KEY'])

    # Get info for all security groups and copy them one-by-one
    g_info = src_client.describe_security_groups(
        GroupNames=grp_names)['SecurityGroups']
    for g in g_info:
        resp = tgt_client.create_security_group(
            GroupName=g['GroupName'], Description=g['Description'])
        new_grp_id = resp['GroupId']
        tgt_client.authorize_security_group_ingress(
            GroupId=new_grp_id, IpPermissions=g['IpPermissions'])
        tgt_client.authorize_security_group_egress(
            GroupId=new_grp_id, IpPermissions=g['IpPermissionsEgress'])


if __name__ == '__main__':
    copy_security_groups('us-east-1', 'ap-south-1', ['rds-public'])
pir
  • 61
  • 4
0

Due to lack of a proper way of doing this online, I created a super simple script to handle it. Have a look if you're interested.

https://github.com/pedropregueiro/migrate-ec2-secgroups

  • This is not really a good candidate for an "answer" submission. Might be useful as a comment when you have enough rep to post those. – Andrew B May 22 '14 at 16:31
0

From the EC2 console, click on Launch Instance and proceed to enter dummy info until you get to the security group section..

From here click on "Select an Existing Security Group", and below you will see all the security groups you have for that particular VPC. You should see a "Copy to New" link under "Actions", use this to copy all of your ACLs to a new SG.

Or I suppose you could use a script - this is faster IMO..

Scott Moore
  • 561
  • 1
  • 4
  • 11
0

I had a similar problem but copying SG across different accounts.

Just specify some CONSTANTS at the beginning and the function copy_sg will copy them.

No error check is in place therefore it the target SG already exists it will fail.

Follow a general solution that can be used also intra-account:

#!/usr/bin/env python3
# coding: utf-8

import boto3
from typing import Any,  List

# This profile needs to be able to assume the specified role in SRC/TGT account
appops_session = boto3.Session(profile_name='YOUR_PRECONFIGURE_PROFILE')

ROLE = "THE ROLE TO BE ASSUMED"  # I presume it is the same in SRC/TGT Account
SRC_ACCOUNT = "YOUR SRC ACCOUNT NUMBER"

TGT_REGION = "eu-central-1"
DST_ACCOUNT = "YOUR TARGET ACCOUNT NUMBER"
TGT_VPC = "vpc-XXXXXXXXXXXXXXX"

region = "ap-southeast-2"
dst_vpc_id = "vpc-XXXXXXXXXXXXXXX"
sg_list = ["sg-XXXXXXXX", "sg-YYYYYYYYY"]

def aws_sts_cred(account, role):
    """Get the STS credential.

    return  credential_object
    """
    sts_creds = {}
    sts_conn = appops_session.client('sts')

    role_arn = "arn:aws:iam::" + account + ":role/" + role
    assumed_role = sts_conn.assume_role(RoleArn=role_arn,
                                        RoleSessionName="TMPROLE")
    sts_creds["aws_access_key_id"] = assumed_role['Credentials']['AccessKeyId']
    sts_creds["aws_secret_access_key"] = assumed_role['Credentials']['SecretAccessKey']
    sts_creds["aws_session_token"] = assumed_role['Credentials']['SessionToken']
    return sts_creds


def aws_conn(service: str, region: str, **kwargs) -> Any:
    """Create a client object."""
    return boto3.client(service, region_name=region, **kwargs)


def dump_sg(client, vpcid: str = "", sgids: List = []) -> List:
    """Dump the specified SG."""
    print(sgids)
    sg_info = client.describe_security_groups(
            Filters = [{'Name': 'group-id', 'Values': sgids}])['SecurityGroups']
    return sg_info


def copy_sg(tgt_client, sgs, vpcid=""):
    for sg in sgs:
        # With no Vpc ID the SG is created in the default VPC.
        resp = tgt_client.create_security_group(
            GroupName=sg['GroupName'], Description=sg['Description'], VpcId=vpcid)
        new_grp_id = resp['GroupId']
        tgt_client.authorize_security_group_ingress(
            GroupId=new_grp_id, IpPermissions=sg.get('IpPermissions', list()))
        if sg.get('IpPermissionsEgress') != []:
            # It doesn't work with an empty list
            tgt_client.authorize_security_group_egress(
                GroupId=new_grp_id, IpPermissions=sg.get('IpPermissionsEgress'))
        print("Create SG {} - \"{}\" - \"{}\" in VPCID: {}".format(new_grp_id, sg['GroupName'], sg['Description'], vpcid))


STS_CRED = aws_sts_cred(SRC_ACCOUNT, ROLE)
STS_CRED_TGT = aws_sts_cred(DST_ACCOUNT, ROLE)

src_client = aws_conn("ec2", region, **STS_CRED)

sg_list = dump_sg(src_client, sgids=sg_list)

tgt_client = aws_conn("ec2", TGT_REGION, **STS_CRED_TGT)

copy_sg(tgt_client, sg_list)

Zioalex
  • 131
  • 6