Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hard to allow connections to/from a plain SecurityGroup object #579

Closed
rix0rrr opened this issue Aug 16, 2018 · 5 comments · Fixed by #582
Closed

Hard to allow connections to/from a plain SecurityGroup object #579

rix0rrr opened this issue Aug 16, 2018 · 5 comments · Fixed by #582
Assignees

Comments

@rix0rrr
Copy link
Contributor

rix0rrr commented Aug 16, 2018

We currently only allow creating connections to and from an IConnectable, which SecurityGroup itself is not.

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Aug 16, 2018

The quick workaround is to make the following class:

class ConnectableSecurityGroup implements IConnectable {
    public readonly connections: Connections;

    constructor(securityGroup: SecurityGroup) {
        this.connections = new Connections(securityGroup);
    }
}

and use as follows:

cluster.connections.allowConnectionsFrom(new ConnectableSecurityGroup(securityGroup), ...);

(But the correct solution will look different)

@eladb
Copy link
Contributor

eladb commented Aug 16, 2018

Just to make sure I understand: we just want to have SecurityGroup implement IConnectable, correct?

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Aug 16, 2018

I think so. Might require reordering some files.

@rix0rrr rix0rrr self-assigned this Aug 16, 2018
@rix0rrr
Copy link
Contributor Author

rix0rrr commented Aug 16, 2018

I think we might take this opportunity to simplify the class diagram of the whole SecurityGroup business somewhat.

Requirements:

machine.connections.allowTo(securityGroup);
machine.connections.allowTo(machine);
machine.connections.allowTo(new AnyIPv4());
machine.connections.allowTo(new DynamoDBInYourVPC());

And other securitygroups or things with securitygroups need to reciprocate connectability whenever that makes sense.

Current state

Right now it looks like this:

                                                                                                                      
                            ┌──────────────────────────────────────────────────────has────────────────┐               
                            │                                                                         │               
                            ▼                                                                         │               
                 ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐        ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐                               │               
                     IConnectionPeer                 IConnectable                                     │               
                 │                     │        │                     │                               │               
                  + toIngressRuleJSON()              + connections     ───────has──────────────┐      │               
                 │+ toEgressRuleJSON() │        │                     │                        │      │               
                  ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─          ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                         │      │               
                          △ △                              △                                   │      │               
                          │ │                              │                                   │      │               
                          │ │                              │                                   │      │               
              ┌───────────┘ └──────────────────┬───────────┘                                   │      │               
              │                                │                                               │      │               
              │                                │                                               │      │               
              │                                │                                               │      │               
              │                                │                                               ▼      │               
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐       ╔═════════════════════╗             ┌────────────────────────────────────────────┐
       ISecurityGroup               ║                     ║██           │                Connections                 │
│                           │       ║       CidrIp        ║██           │                                            │
   + addIngressRule(peer)           ║       AnyIPv4       ║██           │             + defaultPortRange             │
│   + addEgressRule(peer)   │       ║      CidrIPv6       ║██           │                                            │
 ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─        ║       AnyIPv6       ║██           │           + allowTo(connectable)           │
              △                     ║     PrefixList      ║██           │          + allowFrom(connectable)          │
              │                     ║                     ║██           │                                            │
              │                     ╚═════════════════════╝██           │     + allowToDefaultPort(connectable)      │
   ┌─────────────────────┐            ███████████████████████           │    + allowFromDefaultPort(connectable)     │
   │  SecurityGroupRef   │                                              │       + allowInternally(connectable)       │
   │                     │                                              │       + allowToAnyIPv4(connectable)        │
   │  + securityGroupId  │                                              │      + allowFromAnyIPv4(connectable)       │
   └─────────────────────┘                                              │    + allowDefaultPortFrom(connectable)     │
              △                                                         │     + allowDefaultPortTo(connectable)      │
              │                                                         │ + allowDefaultPortInternally(connectable)  │
              │                                                         │ + allowDefaultPortFromAnyIPv4(connectable) │
   ┌─────────────────────┐                                              │                                            │
   │                     │                                              └────────────────────────────────────────────┘
   │    SecurityGroup    │                                                                                            
   │                     │                                                                                            
   └─────────────────────┘                                                                                            

Simple

The simplest thing we could do this the following:

                            ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐                    
                                    IConnectionPeer                            
                            │                             │                    
                                 + toIngressRuleJSON()                         
                            │    + toEgressRuleJSON()     │                    
                                + allowTo(connectable)                         
                            │  + allowFrom(connectable)   │                    
                                    + canInlineRule                            
                            │     + defaultPortRange      │                    
                             ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─                     
                                           △                                   
                                           │                                   
                      ┌────────────────────┴─────────────────────┐             
                      │                                          │             
                      │                                          │             
┌───────────────────────────────────────────┐       ┌─────────────────────────┐
│             SecurityGroupRef              │       │                         │
│                                           │       │  SecurityGrouplessPeer  │
│             + securityGroupId             │       │                         │
│            + defaultPortRange             │       └─────────────────────────┘
│                                           │                    △             
│        + allowToDefaultPort(peer)         │                    │             
│       + allowFromDefaultPort(peer)        │                    │             
│          + allowInternally(peer)          │         ╔═════════════════════╗  
│          + allowToAnyIPv4(peer)           │         ║                     ║██
│         + allowFromAnyIPv4(peer)          │         ║       CidrIp        ║██
│       + allowDefaultPortFrom(peer)        │         ║       AnyIPv4       ║██
│        + allowDefaultPortTo(peer)         │         ║      CidrIPv6       ║██
│    + allowDefaultPortInternally(peer)     │         ║       AnyIPv6       ║██
└───────────────────────────────────────────┘         ║     PrefixList      ║██
                      △                               ║                     ║██
                      │                               ╚═════════════════════╝██
                      │                                 ███████████████████████
                      │                                                        
           ┌─────────────────────┐                                             
           │                     │                                             
           │    SecurityGroup    │                                             
           │                     │                                             
           └─────────────────────┘                                             

This has the following downsides:

  1. ConnectionPeers and things-with-ConnectionPeers are no longer interchangeable. We now have to write:
machine1.securityGroup.allowTo(machine1.securityGroup);

// Instead of
machine1.connections.allowTo(machine1);
  1. SecurityGroupRef now has to be aware of defaultPortRange, which we have to pass upon constructing it. This is not technically correct; the services inside the SG have default port range, not the SG itself. Does not make sense when we have multiple services inside an SG, and also leads to a construction order problem with (for example) RDS clusters, where the dependency chain would be: securityGroup ==(defaultPortRange)==> RDSCluster ==(to create)==> securityGroup. Resolvable with Tokens, but not nice.

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Aug 16, 2018

Okay, I think this is the simplification we're looking for:

                                              ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐                            
                                                                                                   
                                              │     IConnectable      │                            
           ┌─────────────────────────────────▷                         ◁─────────────┐             
           │                                  │     + connections     │              │             
           │                                                                         │             
           │                                  └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘              │             
           │                                              △                          │             
           │       ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐        │                          │             
           │             ISecurityGroupRule               │                          │             
           │       │                             │        │                          │             
           │            + toIngressRuleJSON()             │                          │             
           │       │    + toEgressRuleJSON()     │        │                          │             
           │               + canInlineRule                │                          │             
           │       └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘        │                          │             
           │                △     ▲     △                 │                          │             
           │                │     │     │                 │                          │             
           │    ┌───────────┘     │     └───────────┐     │                          │             
           │    │                 │                 │     │                          │             
           │    │                 │                 │     │                          │             
           │    │                 │                 │     │                          │             
╔═════════════════════╗           │    ┌─────────────────────────┐        ╔═════════════════════╗  
║                     ║██         │    │    SecurityGroupRef     │        ║       Cluster       ║██
║       CidrIp        ║██         │    │                         │        ║    LoadBalancer     ║██
║       AnyIPv4       ║██         │    │    + securityGroupId    │        ║  AutoScalingGroup   ║██
║      CidrIPv6       ║██         │    │                         │──┐     ║         ...         ║██
║       AnyIPv6       ║██         │    │   + addIngressRule()    │  │     ║                     ║██
║     PrefixList      ║██         │    │    + addEgressRule()    │  │     ║   + securityGroup   ║██
║                     ║██         │    └─────────────────────────┘  │     ║                     ║██
╚═════════════════════╝██         │                 △               │     ╚═════════════════════╝██
  █████████│█████████████         │                 │               │       █████████│█████████████
           │                      │                 │               │                │             
           │                      │      ┌─────────────────────┐    │                │             
           │                      │      │                     │    │                │             
           │                      │      │    SecurityGroup    │    │                │             
           │                      │      │                     │    │                │             
           │                      │      └─────────────────────┘    │                │             
           │                      │                                 │                │             
           │                      │                                 │                │             
           │                      │                                 ▼                │             
           │           ┌──────────────────────────────────────────────────┐          │             
           │           │                   Connections                    │          │             
           │           │                                                  │          │             
           │           │               + securityGroupRule                │          │             
           │           │                 + securityGroup?                 │          │             
           │           │               + defaultPortRange?                │          │             
           │           │                                                  │          │             
           └──────────▶│          + allowInternally(connectable)          │◀─────────┘             
                       │          + allowToAnyIPv4(connectable)           │                        
                       │         + allowFromAnyIPv4(connectable)          │                        
                       │       + allowDefaultPortFrom(connectable)        │                        
                       │        + allowDefaultPortTo(connectable)         │                        
                       │                   + allow....                    │                        
                       └──────────────────────────────────────────────────┘                        

Connections has a bunch of attributes to affect whether we actually change security groups or not; we still go through a centralized Connections object to simplify the burden on resource implementors. Connections just knows about security groups, and can touch one or both, depending on the situation (no need for recursion anymore either).

IConnectionPeer renamed to ISecurityGroupRule because that's actually all it represents.

rix0rrr pushed a commit that referenced this issue Aug 16, 2018
Refactoring of the object model for connection/security groups so that a
SecurityGroup object can be used as the target of an .allowTo()
statement:

    cluster.connections.allowTo(securityGroup)

Also add SecurityGroupRef.import() to allow importing a non-constructed
SecurityGroup into the construct tree.

As part of the refactoring:

- Get rid of IDefaultConnectable, the functionality has been folded into
  IConnectable/Connections.
- Get rid of ISecurityGroup.
- Rename IConnectionPeer => ISecurityGroupRule.
- Drastically simplify implementation, get rid of recursion and classes
  to enable the recursion to terminate. All complex logic is now nicely
  contained within Connections.

This change is BREAKING to connections-enabled construct writers, but
transparent to application builders.

Fixes #579.
rix0rrr added a commit that referenced this issue Aug 16, 2018
Refactoring of the object model for connection/security groups so that a
SecurityGroup object can be used as the target of an .allowTo()
statement:

    cluster.connections.allowTo(securityGroup)

SecurityGroupRef is now abstract and needs to be constructed using
SecurityGroupRef.import(). This is also the mechanism for importing
a non-constructed SecurityGroup into the construct tree. 

As part of the refactoring:

- Get rid of IDefaultConnectable, the functionality has been folded into
  IConnectable/Connections.
- Get rid of ISecurityGroup.
- Rename IConnectionPeer => ISecurityGroupRule.
- Drastically simplify implementation, get rid of recursion and classes
  to enable the recursion to terminate. All complex logic is now nicely
  contained within Connections.

This change is BREAKING to connections-enabled construct writers, but
transparent to application builders.

Fixes #579.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants