Proaktive Kontrollen für Lambda mit AWS CloudFormation Guard
AWS CloudFormation Guard ist ein allgemein verwendbares Open-Source-Tool zur Policy-as-Code-Evaluierung. Es kann für präventive Governance und Compliance verwendet werden, indem Infrastructure as Code (IaC)-Vorlagen und Servicezusammenstellungen anhand von Richtlinienregeln validiert werden. Diese Regeln können an die Anforderungen Ihres Teams oder Ihrer Organisation angepasst werden. Für Lambda-Funktionen können die Guard-Regeln verwendet werden, um die Ressourcenerstellung und Konfigurationsupdates zu steuern. Dazu werden die erforderlichen Eigenschaftseinstellungen definiert, die beim Erstellen oder Aktualisieren einer Lambda-Funktion erforderlich sind.
Compliance-Administratoren definieren die Liste der Kontrollen und Governance-Richtlinien, die für die Bereitstellung und Aktualisierung von Lambda-Funktionen erforderlich sind. Plattformadministratoren implementieren die Kontrollen in CI/CD-Pipelines als Pre-Commit-Validierungs-Webhooks mit Code-Repositorys und stellen Entwicklern Befehlszeilentools zur Validierung von Vorlagen und Code auf lokalen Workstations zur Verfügung. Entwickler schreiben Code, validieren Vorlagen mit Befehlszeilentools und übertragen dann den Code in Repositorys, die vor der Bereitstellung in einer AWS-Umgebung automatisch über die CI/CD-Pipelines validiert werden.
Guard ermöglicht es Ihnen wie folgt, Regeln zu schreiben und Kontrollen in einer domainspezifischen Sprache zu implementieren.
Angenommen, Sie möchten, dass Entwickler nur die neuesten Laufzeiten verwenden. Sie könnten zwei verschiedene Richtlinien erstellen. Eine, um Laufzeiten zu bestimmen, die bereits veraltet sind, und eine andere, um Laufzeiten zu bestimmen, die demnächst veraltet sein werden. Dazu könnten Sie die folgende etc/rules.guard-Datei schreiben:
let lambda_functions = Resources.*[ Type == "AWS::Lambda::Function" ] rule lambda_already_deprecated_runtime when %lambda_functions !empty { %lambda_functions { Properties { when Runtime exists { Runtime !in ["dotnetcore3.1", "nodejs12.x", "python3.6", "python2.7", "dotnet5.0", "dotnetcore2.1", "ruby2.5", "nodejs10.x", "nodejs8.10", "nodejs4.3", "nodejs6.10", "dotnetcore1.0", "dotnetcore2.0", "nodejs4.3-edge", "nodejs"] <<Lambda function is using a deprecated runtime.>> } } } } rule lambda_soon_to_be_deprecated_runtime when %lambda_functions !empty { %lambda_functions { Properties { when Runtime exists { Runtime !in ["nodejs16.x", "nodejs14.x", "python3.7", "java8", "dotnet7", "go1.x", "ruby2.7", "provided"] <<Lambda function is using a runtime that is targeted for deprecation.>> } } } }
Nehmen wir nun an, Sie schreiben die folgende iac/lambda.yaml-CloudFormation-Vorlage, die eine Lambda-Funktion definiert:
Fn: Type: AWS::Lambda::Function Properties: Runtime: python3.7 CodeUri: src Handler: fn.handler Role: !GetAtt FnRole.Arn Layers: - arn:aws:lambda:us-east-1:111122223333:layer:LambdaInsightsExtension:35
Nach der Installation des Guard-Dienstprogramms überprüfen Sie die Vorlage:
cfn-guard validate --rules etc/rules.guard --data iac/lambda.yaml
Das Ergebnis sieht folgendermaßen aus:
lambda.yaml Status = FAIL FAILED rules rules.guard/lambda_soon_to_be_deprecated_runtime --- Evaluating data lambda.yaml against rules rules.guard Number of non-compliant resources 1 Resource = Fn { Type = AWS::Lambda::Function Rule = lambda_soon_to_be_deprecated_runtime { ALL { Check = Runtime not IN ["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"] { ComparisonError { Message = Lambda function is using a runtime that is targeted for deprecation. Error = Check was not compliant as property [/Resources/Fn/Properties/Runtime[L:88,C:15]] was not present in [(resolved, Path=[L:0,C:0] Value=["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"])] } PropertyPath = /Resources/Fn/Properties/Runtime[L:88,C:15] Operator = NOT IN Value = "python3.7" ComparedWith = [["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"]] Code: 86. Fn: 87. Type: AWS::Lambda::Function 88. Properties: 89. Runtime: python3.7 90. CodeUri: src 91. Handler: fn.handler } } } }
Guard zeigt Entwicklern auf ihren lokalen Workstations, dass sie die Vorlage aktualisieren müssen, um eine Laufzeit zu verwenden, die von der Organisation zugelassen ist. Dies geschieht, bevor ein Commit in ein Code-Repository übernommen wird und anschließend Prüfungen innerhalb einer CI/CD-Pipeline fehlschlagen. Ihre Entwickler erhalten direktes Feedback, wie sie konforme Vorlagen entwickeln und können ihre Zeit darauf verwenden, Code zu schreiben, der geschäftlichen Nutzen bietet. Diese Kontrolle kann vor der Bereitstellung auf der lokalen Entwickler-Workstation, in einem Pre-Commit-Validierungs-Webhook und/oder in der CI/CD-Pipeline angewendet werden.
Einschränkungen
Wenn Sie AWS Serverless Application Model-(AWS SAM)-Vorlagen verwenden, um Lambda-Funktionen zu definieren, beachten Sie, dass Sie die Guard-Regel aktualisieren müssen, um nach dem Ressourcentyp AWS::Serverless::Function wie folgt zu suchen.
let lambda_functions = Resources.*[ Type == "AWS::Serverless::Function" ]
Guard erwartet außerdem, dass die Eigenschaften in der Ressourcendefinition enthalten sind. AWS SAM-Vorlagen ermöglichen die Angabe von Eigenschaften in einem separaten Globals-Abschnitt. Eigenschaften, die im Globals-Abschnitt definiert sind, werden nicht mit Ihren Guard-Regeln validiert.
Beachten Sie, dass Guard, wie in der Dokumentation zur Fehlerbehebung bei Guard beschrieben, keine intrinsischen Kurzformen wie !GetAtt oder !Sub unterstützt, sondern stattdessen die Verwendung der erweiterten Formen erfordert: Fn::GetAtt und Fn::Sub. (Im vorherigen Beispiel wird die Role-Eigenschaft nicht ausgewertet, daher wurde der Einfachheit halber die intrinsische Kurzform verwendet.)