Stavo cercando la stessa funzionalità. Mi è venuto in mente l'utilizzo di uno stack nidificato come suggerito da SpoonMeiser, ma poi mi sono reso conto che ciò di cui avevo effettivamente bisogno erano funzioni personalizzate. Fortunatamente CloudFormation consente l'uso di AWS :: CloudFormation :: CustomResource che, con un po 'di lavoro, consente di fare proprio questo. Questo sembra eccessivo solo per le variabili (qualcosa che direi che avrebbe dovuto essere in CloudFormation in primo luogo), ma ottiene il lavoro fatto e, inoltre, consente tutta la flessibilità di (scegli il tuo python / nodo /Giava). Va notato che le funzioni lambda costano denaro, ma qui stiamo parlando di centesimi a meno che tu non crei / elimini le tue pile più volte all'ora.
Il primo passo è fare una funzione lambda in questa pagina che non fa altro che prendere il valore di input e copiarlo nell'output. Potremmo avere la funzione lambda fare ogni sorta di cose folli, ma una volta che abbiamo la funzione di identità, qualsiasi altra cosa è facile. In alternativa, potremmo avere la funzione lambda creata nello stack stesso. Dal momento che uso molti stack in 1 account, avrei un sacco di funzioni e ruoli lambda rimanenti (e tutti gli stack devono essere creati con --capabilities=CAPABILITY_IAM
, poiché ha anche bisogno di un ruolo.
Crea la funzione lambda
- Vai alla home page lambda e seleziona la tua regione preferita
- Seleziona "Funzione vuota" come modello
- Fai clic su "Avanti" (non configurare alcun trigger)
- Compilare:
- Nome: CloudFormationIdentity
- Descrizione: restituisce ciò che ottiene, supporto variabile in Cloud Formation
- Runtime: python2.7
- Tipo di inserimento codice: modifica codice in linea
- Codice: vedi sotto
- handler:
index.handler
- Ruolo: creare un ruolo personalizzato. A questo punto si apre un popup che consente di creare un nuovo ruolo. Accetta tutto su questa pagina e fai clic su "Consenti". Creerà un ruolo con le autorizzazioni per pubblicare nei log di cloudwatch.
- Memoria: 128 (questo è il minimo)
- Timeout: 3 secondi (dovrebbe essere abbondante)
- VPC: nessun VPC
Quindi copia e incolla il codice qui sotto nel campo del codice. La parte superiore della funzione è il codice del modulo python cfn-response , che viene installato automaticamente solo se la funzione lambda viene creata tramite CloudFormation, per qualche strano motivo. La handler
funzione è piuttosto autoesplicativa.
from __future__ import print_function
import json
try:
from urllib2 import HTTPError, build_opener, HTTPHandler, Request
except ImportError:
from urllib.error import HTTPError
from urllib.request import build_opener, HTTPHandler, Request
SUCCESS = "SUCCESS"
FAILED = "FAILED"
def send(event, context, response_status, reason=None, response_data=None, physical_resource_id=None):
response_data = response_data or {}
response_body = json.dumps(
{
'Status': response_status,
'Reason': reason or "See the details in CloudWatch Log Stream: " + context.log_stream_name,
'PhysicalResourceId': physical_resource_id or context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': response_data
}
)
if event["ResponseURL"] == "http://pre-signed-S3-url-for-response":
print("Would send back the following values to Cloud Formation:")
print(response_data)
return
opener = build_opener(HTTPHandler)
request = Request(event['ResponseURL'], data=response_body)
request.add_header('Content-Type', '')
request.add_header('Content-Length', len(response_body))
request.get_method = lambda: 'PUT'
try:
response = opener.open(request)
print("Status code: {}".format(response.getcode()))
print("Status message: {}".format(response.msg))
return True
except HTTPError as exc:
print("Failed executing HTTP request: {}".format(exc.code))
return False
def handler(event, context):
responseData = event['ResourceProperties']
send(event, context, SUCCESS, None, responseData, "CustomResourcePhysicalID")
- Fai clic su "Avanti"
- Fai clic su "Crea funzione"
Ora puoi testare la funzione lambda selezionando il pulsante "Test" e selezionando "CloudFormation Create Request" come modello di esempio. Dovresti vedere nel tuo registro che le variabili che gli sono state fornite vengono restituite.
Usa la variabile nel tuo modello CloudFormation
Ora che abbiamo questa funzione lambda, possiamo usarla nei modelli CloudFormation. Prima prendi nota della funzione lambda Arn (vai alla home page lambda , fai clic sulla funzione appena creata, l'Arn dovrebbe essere in alto a destra, qualcosa del genere arn:aws:lambda:region:12345:function:CloudFormationIdentity
).
Ora nel tuo modello, nella sezione delle risorse, specifica le tue variabili come:
Identity:
Type: "Custom::Variable"
Properties:
ServiceToken: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"
Arn: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"
ClientBucketVar:
Type: "Custom::Variable"
Properties:
ServiceToken: !GetAtt [Identity, Arn]
Name: !Join ["-", [my-client-bucket, !Ref ClientName]]
Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName]]]]
ClientBackupBucketVar:
Type: "Custom::Variable"
Properties:
ServiceToken: !GetAtt [Identity, Arn]
Name: !Join ["-", [my-client-bucket, !Ref ClientName, backup]]
Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName, backup]]]]
Per prima cosa specifico una Identity
variabile che contiene l'Arn per la funzione lambda. Mettendo questo in una variabile qui, significa che devo specificarlo solo una volta. Faccio tutte le mie variabili di tipo Custom::Variable
. CloudFormation ti consente di utilizzare qualsiasi nome-tipo a partire da Custom::
per risorse personalizzate.
Si noti che la Identity
variabile contiene due volte Arn per la funzione lambda. Una volta per specificare la funzione lambda da usare. La seconda volta come valore della variabile.
Ora che ho la Identity
variabile, posso definire nuove variabili usando ServiceToken: !GetAtt [Identity, Arn]
(penso che il codice JSON dovrebbe essere qualcosa di simile "ServiceToken": {"Fn::GetAtt": ["Identity", "Arn"]}
). Creo 2 nuove variabili, ognuna con 2 campi: Nome e Arn. Nel resto del mio modello posso usare !GetAtt [ClientBucketVar, Name]
o !GetAtt [ClientBucketVar, Arn]
quando ne ho bisogno.
Avvertenza
Quando lavori con risorse personalizzate, se la funzione lambda si arresta in modo anomalo, rimani bloccato tra 1 e 2 ore, perché CloudFormation attende una risposta dalla funzione (arrestata) per un'ora prima di arrendersi. Pertanto potrebbe essere utile specificare un timeout breve per lo stack durante lo sviluppo della funzione lambda.