0

I'm trying to create security groups in pulumi with inline rules, specifically rules that reference another security group as a source. None of these group exist yet and need to be created in a loop from a variable as there may be quite a lot of them.

Here's a example of what the variables looks like:

compute:security_groups:
- name: load-balancer
  inbound:
  - cidr_blocks: null
    from_port: 80
    protocol: tcp
    source_security_group: cache
    to_port: 80
  - cidr_blocks: null
    from_port: 22
    protocol: tcp
    source_security_group: logging
    to_port: 22
- name: cache
  inbound:
  - cidr_blocks: null
    from_port: 6379
    protocol: tcp
    source_security_group: load-balancer
    to_port: 6379
- name: logging
  inbound:
  - cidr_blocks: null
    from_port: 22
    protocol: tcp
    source_security_group: cache
    to_port: 22
  - cidr_blocks: null
    from_port: 5044
    protocol: tcp
    source_security_group: load-balancer
    to_port: 5044

We should create a security group called name and include an inline rule for each item under inbound. The source security group needs to to point back to the group referenced in source_security_group

The closest I've gotten is to create the rules first with as a SecurityGroupIngressArgs then add them to a seperatly created group. Something like:

env_name = pulumi.get_stack()
default_tags = {'resource-group': env_name, 'environment': env_name, 'managed-by': "pulumi"}


### Securty groups
# Create groups
sg_list = []
for sg in config.require_object('security_groups'):

    # create rules
    inbound_list = []
    for item in sg['inbound']:
        source_group_name = env_name + '-' + item['source_security_group']
        inbound_list.append(aws.ec2.SecurityGroupIngressArgs(
            from_port   = item['from_port'],
            to_port     = item['to_port'],
            protocol    = item['protocol'],
            security_groups = sg_list[source_group_name.id]
        ))

    # create groups
    sg_name = env_name + '-' + sg.get('name')
    sg_list.append(aws.ec2.SecurityGroup(sg_name,
        description = sg.get('description'),
        vpc_id      = kv_vpc['id'],
        ingress     = inbound_list,
        egress      = outbound_list,
        tags        = {**default_tags,**{'Name': sg_name}}
        )
    )

This approach work fine for cidr blocks but with security groups as the source I can't reference security group id's that have not been created yet. I'm not sure how to structure this with pulumi.

Setanta
  • 941
  • 1
  • 12
  • 24
  • Is the error happening in the code above or is that a smaller part of a much larger file? – Piers Karsenbarg Nov 25 '20 at 14:20
  • It's a smaller part of a larger file. However this is more of a 'how do I approach this' question, rather then a specific error. I don't how how to handle `security_groups` in pulumi in this senario. – Setanta Nov 25 '20 at 14:46
  • did you get an answer to this? – Oxax Mar 11 '22 at 08:05

2 Answers2

0

The key thing to remember is that when you're writing this, and when it's running some of the resources won't have been created yet (either because it takes a while for AWS to create things or because it hasn't got to that bit in the code yet).

Pulumi handles this by using what we call "inputs" and "outputs" (if you know javascript/typescript then you'll know what I mean by a promise), and more specifically you'll want to look at the apply example where it uses a lambda to get the variables.

In some cases you'll be able to use the array of security groups directly. Here's an example in the docs:

import pulumi
import pulumi_aws as aws

size = 't2.micro'
ami = aws.get_ami(most_recent="true",
              owners=["137112412989"],
              filters=[{"name":"name","values":["amzn-ami-hvm-*"]}])

group = aws.ec2.SecurityGroup('webserver-secgrp',
    description='Enable HTTP access',
    ingress=[
        { 'protocol': 'tcp', 'from_port': 22, 'to_port': 22, 'cidr_blocks': ['0.0.0.0/0'] }
    ])

server = aws.ec2.Instance('webserver-www',
    instance_type=size,
    vpc_security_group_ids=[group.id], # reference security group from above
    ami=ami.id)

pulumi.export('publicIp', server.public_ip)
pulumi.export('publicHostName', server.public_dns)

(link to example in docs)

Piers Karsenbarg
  • 3,105
  • 5
  • 31
  • 67
0

Create a security group rule resource after creating all security group and associate the rule to required security group.

sg_1 = aws.ec2.SecurityGroup(
     'sg1',
      description='Security group',                                     
)

sg_2 = aws.ec2.SecurityGroup(
     'sg2',
      description='Security group',
      ingress=[
        {'protocol': 'tcp',
        'description': "allow http access from sg1",
        'from_port': 8080,
        'to_port': 8080,
        'security_groups': [sg_1.id]
        }
      ]                                       
     )

sg1_rule = aws.ec2.SecurityGroupRule(
     "allow-s2",
     type="ingress",
     description= "allow http access from sg2"
     protocol="tcp",
     to_port= 8080,
     from_port= 8080,
     security_group_id=sg_1.id,
     source_security_group_id=vsg_2.id
    )
Oxax
  • 91
  • 8