2014-04-28 8 views
11

Abbiamo un modello CloudFormation che crea un'istanza EC2 e di un gruppo di protezione (tra molte altre risorse), ma abbiamo bisogno di essere in grado di aggiungere qualche ulteriore preesistente gruppi di sicurezza per la stessa istanza EC2.Aggiungere un elenco sconosciuta dimensioni dei gruppi di protezione a un'istanza EC2

Il problema che abbiamo è che il numero di pre-esistenti gruppi di protezione non sarà sempre lo stesso, e vogliamo avere un unico modello che gestirà tutti i casi.

Attualmente, abbiamo un parametro di input che assomiglia a questo:

"WebTierSgAdditional": { 
    "Type": "String", 
    "Default": "", 
    "Description": "" 
} 

Passiamo In questo parametro è una stringa delimitata da virgole di gruppi di protezione pre-esistenti, come ad esempio 'sg-abc123,sg-abc456'.

Il tag SecurityGroup dell'istanza EC2 simile a questa:

"SecurityGroups": [ 
    { 
    "Ref": "WebSg" 
    }, 
    { 
    "Ref": "WebTierSgAdditional" 
    } 
] 

Con questo codice, quando l'istanza viene creato, otteniamo questo errore nella console AWS:

necessario utilizzare usa group-id o group-name per tutti i gruppi di sicurezza, non entrambi allo stesso tempo

Il riferimento sopra "WebSg" è uno dei gruppi di sicurezza che sono cr mangiato altrove nel modello. Questo stesso errore appare se passiamo in un elenco di nomi di gruppi piuttosto che in un elenco di Id di gruppo attraverso il parametro di input.

Quando cambiamo il campo "Tipo" del parametro di ingresso di essere 'CommaDelimitedList', otteniamo un errore dicendo:

Valore della SecurityGroups proprietà deve essere di tipo List di String

Ovviamente non è possibile unire una lista con una stringa per renderla una nuova lista.

Quando il parametro contiene un solo sg id, tutto viene creato con successo, però, abbiamo bisogno di avere la capacità di aggiungere più di un solo sg id.

Abbiamo provato molte combinazioni diverse di utilizzo Fn::Join all'interno del tag SecurityGroups, ma nulla sembra funzionare. Quello di cui abbiamo veramente bisogno è una sorta di funzione 'Esplodi' per estrarre i singoli ID dalla stringa dei parametri.

Qualcuno sa di un bel modo per ottenere questo lavoro?

+0

Il motivo è, per le istanze in EC2-classico, è necessario fornire il nome SG mentre le istanze all'interno di VPC, è necessario fornire SG ID. Quindi l'errore 'Devi usare sia l'id di gruppo o il nome di gruppo per tutti i gruppi di sicurezza, non entrambi allo stesso tempo 'è semplice. In altre parole, puoi avere l'istanza in esecuzione in EC2-classic OR in VPC ... ma non in entrambi. È necessario escogitare un altro approccio per passare solo il nome SG o solo gli ID SG all'istanza. – slayedbylucifer

+0

I nostri gruppi di sicurezza sono creati all'interno di un VPC, quindi la funzione 'Rif' restituisce l'ID SG, non il nome SG. Il problema sembra essere che Cloudformation stia interpretando il nostro parametro stringa di ids ('sg-abc123, sg-abc456') come un nome SG, e dobbiamo in qualche modo convertirlo in un elenco di SG ID –

risposta

10

Come avete scoperto, il problema è che è necessario inviare un elenco di stringhe come gruppi di sicurezza e sebbene CloudFormation offra un metodo per unire un elenco di stringhe in un'unica stringa delimitata, non lo fa fornire un metodo semplice per dividere una stringa delimitata in un elenco di stringhe.

Sfortunatamente l'unico modo in cui so come farlo è con uno stack nidificato. È possibile utilizzare il tipo di parametro "CommaDelimitedList" per dividere una stringa delimitata da virgole in una lista di stringhe.

Il metodo di base è questo:

  1. Crea il tuo gruppo di protezione nel modello cloudformation.
  2. Unisci l'ID del gruppo di sicurezza con l'elenco dei gruppi di sicurezza utilizzando Fn :: Join.
  3. Passa l'elenco a uno stack nidificato (una risorsa di tipo AWS :: CloudFormation :: Stack).
  4. Prendere il parametro come tipo "CommaDelimitedList" nel modello separato.
  5. Passare il parametro ref nella dichiarazione di istanza EC2.

Ho provato questo con i seguenti 2 modelli e che sta funzionando:

template Main:

{ 
    "AWSTemplateFormatVersion": "2010-09-09",                         
    "Parameters" : { 
     "SecurityGroups" : {                   
      "Description" : "A comma separated list of security groups to merge with the web security group", 
      "Type" : "String" 
     } 
    }, 
    "Resources" : { 
     "WebSg" : ... your web security group here, 
     "Ec2Instance" : { 
      "Type" : "AWS::CloudFormation::Stack", 
      "Properties" : { 
       "TemplateURL" : "s3 link to the other stack template", 
       "Parameters" : { 
        "SecurityGroups" : { "Fn::Join" : [ ",", [ { "Ref" : "WebSg" }, { "Ref" : "SecurityGroups" } ] ] }, 
       } 
      } 
     } 
    } 
} 

Il modello nidificato (collegata al dal "TemplateURL" di cui sopra):

{ 
    "AWSTemplateFormatVersion": "2010-09-09", 
    "Parameters" : { 
     "SecurityGroups" : { 
      "Description" : "The Security Groups to launch the instance with", 
      "Type" : "CommaDelimitedList" 
     }, 
    } 
    "Resources" : { 
     "Ec2Instance" : { 
      "Type" : "AWS::EC2::Instance", 
      "Properties" : {          
       ... etc   
       "SecurityGroupIds" : { "Ref" : "SecurityGroups" } 
      } 
     } 
    } 
} 

Mi piacerebbe sapere se c'è un modo migliore per farlo. Come dici tu, ha davvero bisogno di una funzione di esplosione.

+0

Sigh, non c'è ancora modo migliore per farlo nel 2015? – bdrx

+0

Mi odio per averlo implementato in questo modo, ma grazie per la risposta. Questa soluzione non mi è mai venuta in mente. –

+0

Vedere la mia risposta su come eseguire questa operazione senza un substack. –

3

C'è un'altra soluzione che ho ottenuto dal supporto e ho trovato più bello.

In sostanza si è appena ogni gruppo di protezione per il suo indice dall'elenco e poi aggiunge quello interno alla fine.

"SecurityGroupList": { 
    "Description": "List of existing security groups", 
    "Type": "CommaDelimitedList" 
}, 
... 
"InternalSecurityGroup": { 
    "Type": "AWS::EC2::SecurityGroup" 
}, 
... 
"SecurityGroupIds": [ 
    { 
     "Fn::Select": [ 
      "0", 
      { 
       "Ref": "SecurityGroupList" 
      } 
     ] 
    }, 
    { 
     "Fn::Select": [ 
      "1", 
      { 
       "Ref": "SecurityGroupList" 
      } 
     ] 
    }, 
    { 
     "Fn::Select": [ 
      "2", 
      { 
       "Ref": "SecurityGroupList" 
      } 
     ] 
    }, 
    { 
     "Ref": "InternalSecurityGroup" 
    } 
], 

Spero che questo aiuti chiunque altro.

+1

Questa non è affatto una soluzione sbagliata, ma come gestisci un numero variabile di SecurityGroups nell'elenco? –

1

si può effettivamente scrivere la funzione di conversione necessaria lambda senza creare un sottocatasta, per ottenere la necessaria List-String.

Ad esempio: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/walkthrough-custom-resources-lambda-lookup-amiids.html

In realtà, questa funzione non ha realmente bisogno di fare qualcosa di diverso elenco ricevere e restituire indietro. Avevo uno scenario simile in cui avevo un List-AWS :: EC2 :: Subnet :: Id- e dovevo passarlo a una risorsa che richiedeva una List-String.

processo:

Definire una LambdaExecutionRole.

Definire una funzione ListToStringList di tipo AWS :: Lambda :: Funzione, aggiungere codice che ritorna nei dati cfnresponse {'Result': event ['ResourceProperties'] ['List']}.

definire una risorsa personalizzato tipo MyList personalizzati :: MyList, danno il ServiceToken del GetAtt del ListToStringListFunction Arn. Passa anche all'elenco come una proprietà che rimpiazza l'elenco originale.

MyList di riferimento con Fn :: GetAtt (MyList, Risultato)

4

AWS introdotto Fn::Split in January 2017 e questo è ora possibile. Non è bello, ma si sta essenzialmente la conversione di due liste in stringhe con Fn::Join, e quindi la conversione delle stringhe di nuovo a una lista con Fn::Split.

Parameters: 

    WebTierSgAdditional: 
     Type: CommaDelimitedList 
     Default: '' 
     Description: '' 

Conditions: 

    HasWebTierSgAdditional: !Not [ !Equals [ '', !Select [ 0, !Ref WebTierSgAdditional ] ] ] 

Resources: 

    WebSg: 
     Type: AWS::EC2::SecurityGroup 
     Properties: 
      # ... 

    Ec2Instance: 
     Type: AWS::EC2::Instance 
     Properties: 
      # ... 
      SecurityGroupIds: !Split 
        - ',' 
        - !Join 
         - ',' 
         - - !Ref WebSg 
          - !If [ HasWebTierSgAdditional, !Join [ ',', !Ref WebTierSgAdditional ], !Ref 'AWS::NoValue' ] 

WebTierSgAdditional inizia come un elenco, ma viene convertito in una stringa con ogni elemento separato da una virgola via !Join [ ',', !Ref WebTierSgAdditional ]. Questo è incluso in un altro elenco che include !Ref WebSg che viene anche convertito in una stringa con ogni elemento separato da una virgola. !Split prenderà una stringa e dividerà gli elementi in un elenco separato da una virgola.

1

una molto più semplice soluzione di linea 2 avrebbe seguito:

Se si dispone di un comune AppSecurityGroups come di seguito nelle mappature o può essere come parametro:

"AppSecurityGroups" : "sg-xxx,sg-yyyy,sg-zzz" 

e il secondo gruppo di protezione (serivice specifico) ServiceSecurityGroup con valore sg-aaa come parametro nel CFT.

Scrive una condizione sul gruppo di sicurezza del servizio per verificare se è None o no.

"Conditions": { 
    "IsEmptySSG": { 
    "Fn::Equals": [ 
     {"Ref": ServiceSecurityGroup"}, 
     "None" 
    ] 
    } 
} 

quindi unire i gruppi di protezione in base alla condizione che ServiceSecurityGroup non è vuoto.

"SecurityGroups" : { 
    "Fn::If" : [ 
    "IsEmptySSG", 
    {"Fn::Split" : [ "," , {"Ref" : "AppSecurityGroups"} ]}, 
    {"Fn::Split" : [ "," , 
     { "Fn::Join" : [ ",", [{"Ref" : "AppSecurityGroups"}, { "Ref" : "ServiceSecurityGroup" }]]} 
     ] 
    } 
    ] 
}, 

Questo sarebbe aggiungere dinamicamente 2 liste CSV dei gruppi di protezione in un unico per essere utilizzato da risorse AWS.

L'ho provato e utilizzato per un problema simile, ha funzionato molto bene.

+0

L'unico problema con questa soluzione è che è necessario utilizzare un tipo di parametro stringa per il gruppo di sicurezza addizione e inserire gli ID del gruppo di sicurezza in formato separato da virgole piuttosto che utilizzare l'elenco quale sarebbe più pulito. – CarlR