Némi IT és némi felhő újra
IaC eszközökkel dolgozom már nem is igazán tudom mióta. Az AWS CloudFormation-nel kezdtem valamikor 2014 körül (nem biztos, ez a ködös múltba vész)
Amikor elkezdtem a Terraformról tanulni, bennem volt a félelem, hogy nem fogok teljes AWS funkcionalitást kapni. A CloudFormation natív AWS eszköz. Valami amit egy külső gyártó fejleszt - elméletben - csak követheti a szolgáltató natív eszközét.
Elkezdtem Terraformot használni, mert ez volt az ügyfél elvárása, tehát a váltás nem az én döntésem volt. A fenti félelmem akkor vált kicsit valósággá amikor az ügyfél nem követte az AWS Provider verzióit megfelelően a saját deployment agent-jein (tehát ez nem róható fel sem a HashiCorpnak, sem a Terraform közösségnek). Tehát tulajdonképpen nem látszott valós lemaradás a Terraform oldalán. Emellett Terraform kódot írni sokkal kényelmesebb, sokkal több lehetőséget nyújt amikor feldolgozni, konvertálni kell, a rendelkezésre álló információt.
Egy pár hete, kb. három év kizárólagos Terraform munka után belecsöppentem újra egy CloudFormation projectbe.
Van egy - azt hittem - szuper egyszerű feladat. Publikálni egy Cognito User Pool Client titkos kulcsot az SSM Parameter Store-ba, titkosítva.
Terraformban ez így néz ki:
// Create Cognito User Pool
resource "aws_cognito_user_pool" "pool" {
name = "pool"
}
// Create Cognito User Pool Client
resource "aws_cognito_user_pool_client" "client" {
name = "client"
user_pool_id = aws_cognito_user_pool.pool.id
generate_secret = true
}
// Publish to SSM Parameter Store
resource "aws_ssm_parameter" "secret" {
name = "/production/cognito/clientSecret"
type = "SecureString"
value = ${aws_cognito_user_pool_client.client.client_secret}
}
És kész is vagyunk.
Próbáljuk meg ugyanezt a CloudFormation-ben.
Vajon a AWS::Cognito::UserPoolClient objektum, ki tudja-e exportálni a titkos kulcsot? Nem. Forrás: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html
Vajon a AWS::SSM::Parameter objektum tud-e SecureString értéket létrehozni? Nem. Forrás: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-parameter.html
Itt van ahol a fenti teóriám "A CloudFormation-nek előrébb kell járnia mint a Terraformnak" megbukik.
Sok mindennel próbálkoztam sikertelenül, hogy megoldjam ezt. Végülis a következő kódrészlet működött (egy megjegyzés: a Python kódban, az import cfnresponse nem az én trehányságom miatt van külön sorban. Ez kell az AWS lambdának, hogy észrevegye, kell neki a cfnresponse.py és belerakja a deployment során a zip fájlba, ugyanis nem része a pip repónak):
Resources:
# Create Cognito User Pool
UserPool:
Type: "AWS::Cognito::UserPool"
Properties:
UserPoolName: pool
# Create Cognito User Pool Client
UserPoolClient:
Type: "AWS::Cognito::UserPoolClient"
Properties:
AccessTokenValidity: 15
AllowedOAuthFlowsUserPoolClient: false
ClientName: client
GenerateSecret: true
# You need a lambda to
# - read from the cognito user pool client
# - write to the parameter store
# - report back to the CloudFormation when finished
CognitoSecretExporterLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: CognitoSecretExporter
Runtime: python3.9
Role: !GetAtt CognitoSecretExporterExecutionRole.Arn
Handler: index.handler
Timeout: 30
Environment:
Variables:
CognitoUserPoolId: !Ref UserPool
CognitoUserPoolClientId: !Ref UserPoolClient
ssmParameterName: /production/cognito/ClientSecret
Code:
ZipFile: |
import boto3, os
import cfnresponse
def handler(event, context):
CognitoUserPoolId = os.environ['CognitoUserPoolId']
CognitoUserPoolClientId = os.environ['CognitoUserPoolClientId']
ssmParameterName = os.environ['ssmParameterName']
# Read Cognito
cognito = boto3.client('cognito-idp')
response = cognito.describe_user_pool_client(
UserPoolId = CognitoUserPoolId,
ClientId = CognitoUserPoolClientId
)
cognitoClientSecret = response['UserPoolClient']['ClientSecret']
print(cognitoClientSecret)
ssm = boto3.client('ssm')
# Write to parameter store
response = ssm.put_parameter(
Name = ssmParameterName,
Description = '[CF] Cognito Client Secret used by the WebApp',
Value = cognitoClientSecret,
Type = 'SecureString',
KeyId = 'alias/aws/ssm',
Overwrite = True,
Tier='Standard'
)
# Report success to CloudFormation
responseData = {}
responseData['Data'] = 120
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
# Trigger the lambda from the CloudFormation stack
CognitoSecretExporterInvoke:
Type: AWS::CloudFormation::CustomResource
DependsOn: CognitoSecretExporterLambda
Version: "1.0"
Properties:
ServiceToken: !GetAtt CognitoSecretExporterLambda.Arn
# IAM Role for the lambda above
CognitoSecretExporterExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: CognitoSecretExporterExecutionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: root
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: EnablePutLogEvents
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- '*'
- Sid: ReadCognito
Effect: Allow
Action:
- cognito-idp:DescribeUserPoolClient
Resource:
- !GetAtt UserPool.Arn
- Sid: ParamStore
Effect: Allow
Action:
- ssm:DeleteParameter
- ssm:PutParameter
- ssm:GetParameter
Resource:
- !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/production/cognito/ClientSecret
Használtad már a Terraform-t Azure-el?
VálaszTörlésIgen, Terraformozom az Azure-ban, most napi munka szinten. Ahonnan a fenti cikk jön az egy community project az AWS-ben.
Törlés