Migrating from Serverless Framework to AWS CDK: Part 5 - Authentication, Authorization, and IAM

Implement robust authentication with Cognito, API Gateway authorizers, and fine-grained IAM policies when migrating from Serverless Framework to AWS CDK.

Woche 9 unserer CDK-Migration. Alles lief reibungslos, bis unser Head of Security mit einer einzigen Frage in das morgendliche Standup kam: "Welche Lambda-Funktionen können auf Kundenzahlungsdaten zugreifen?"

Dreiundzwanzig Gesichter starrten ihn schweigend an. Unser Serverless Framework-Setup war über 18 Monate organisch gewachsen. Funktionen hatten "*" IAM-Berechtigungen, weil es "schneller zu shippen war". Autorisierungslogik war über 12 verschiedene Custom Authorizer verstreut. Wir hatten keinen Audit-Trail, wer auf was zugreifen konnte.

Diese Frage löste ein 3-wöchiges Sicherheitsaudit aus, das 47 überprivilegierte Funktionen und eine potenzielle Compliance-Strafe von $180K aufdeckte. Das ist die Geschichte des Wiederaufbaus von Enterprise-Grade-Authentifizierung und -Autorisierung während einer Live-Migration - ohne eine einzige Benutzersitzung zu brechen.

Seriennavigation:

Das Authentifizierungs-Albtraum-Audit#

Bevor wir etwas reparieren konnten, mussten wir verstehen, was wir hatten. Das Audit enthüllte unsere Authentifizierungshölle:

Die Serverless Framework-Realitätsprüfung#

Benutzerverwaltung: Drei verschiedene Cognito-Pools in verschiedenen Umgebungen, manuell erstellt, null Dokumentation der benutzerdefinierten Attribute.

Autorisierung: 12 verschiedene Lambda-Authorizer, jeder mit unterschiedlicher JWT-Validierungslogik, kein Caching, durchschnittlich 400ms Autorisierungslatenz.

IAM-Berechtigungen: 47 Lambda-Funktionen mit Wildcard-Berechtigungen. Unsere kritischste Zahlungsfunktion hatte "*" Zugriff auf alle DynamoDB-Tabellen.

Secrets: API-Keys in Umgebungsvariablen hartcodiert, umgebungsübergreifend geteilt, zuletzt rotiert "irgendwann 2022".

Audit-Trail: Keiner. Null Protokollierung von Autorisierungsentscheidungen. Keine Möglichkeit zu beantworten "wer hat wann auf was zugegriffen".

Die Geschäftsauswirkung#

  • Compliance-Risiko: $180K potenzielle GDPR-Strafe für zu breiten Datenzugriff
  • Performance-Auswirkung: 400ms durchschnittliche Autorisierungslatenz (28% der Gesamtanfrage-Zeit)
  • Betriebsaufwand: 3 Stunden/Woche zur Lösung von Authentifizierungsproblemen
  • Sicherheitsschuld: 47 Funktionen mit unnötigen Berechtigungen

Produktionsreife Cognito-Implementierung#

Nach dem Audit bauten wir die Authentifizierung mit Enterprise-Kontrollen neu auf. Hier ist der kampferprobte Ansatz:

YAML
# serverless.yml
resources:
  Resources:
    UserPool:
      Type: AWS::Cognito::UserPool
      Properties:
        UserPoolName: ${self:service}-${opt:stage}-users
        Schema:
          - Name: email
            Required: true
            Mutable: false
          - Name: role
            AttributeDataType: String
            Mutable: true
        AutoVerifiedAttributes:
          - email
        Policies:
          PasswordPolicy:
            MinimumLength: 8
            RequireUppercase: true
            RequireLowercase: true
            RequireNumbers: true
            RequireSymbols: true

    UserPoolClient:
      Type: AWS::Cognito::UserPoolClient
      Properties:
        ClientName: ${self:service}-${opt:stage}-client
        UserPoolId: !Ref UserPool
        GenerateSecret: false
        ExplicitAuthFlows:
          - ALLOW_USER_PASSWORD_AUTH
          - ALLOW_REFRESH_TOKEN_AUTH

Der Enterprise-Grade CDK-Ansatz#

Hier ist die Cognito-Implementierung, die das SOC 2-Audit bestanden hat und 180K+ Benutzer verarbeitet:

TypeScript
// lib/constructs/auth/production-cognito.ts
import {
  UserPool,
  UserPoolClient,
  AccountRecovery,
  Mfa,
  UserPoolOperation,
  StringAttribute,
  ClientAttributes,
  OAuthScope,
  UserPoolDomain,
  CognitoUserPoolsAuthorizer
} from 'aws-cdk-lib/aws-cognito';
import { Duration, RemovalPolicy, Tags } from 'aws-cdk-lib';
import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs';
import { Alarm, Metric, TreatMissingData } from 'aws-cdk-lib/aws-cloudwatch';

export class ProductionCognitoAuth extends Construct {
  public readonly userPool: UserPool;
  public readonly userPoolClient: UserPoolClient;
  public readonly authorizer: CognitoUserPoolsAuthorizer;

  constructor(scope: Construct, id: string, props: {
    stage: string;
    domainPrefix?: string;
    callbackUrls?: string[];
    api: RestApi;
  }) {
    super(scope, id);

    // Benutzerpool mit audit-konformen Einstellungen erstellen
    this.userPool = new UserPool(this, 'EnterpriseUserPool', {
      userPoolName: `my-service-${props.stage}-users-v2`,
      // Erweiterte Sicherheit: keine Selbstregistrierung in Produktion
      selfSignUpEnabled: props.stage !== 'prod',
      signInAliases: {
        email: true,
        username: false,  // Nur E-Mail-Anmeldung reduziert Angriffsfläche
      },
      signInCaseSensitive: false,
      autoVerify: { email: true },

      // SOC 2-konforme Passwort-Richtlinie
      passwordPolicy: {
        minLength: 14,  // Nach Audit von 12 erhöht
        requireLowercase: true,
        requireUppercase: true,
        requireDigits: true,
        requireSymbols: true,
        tempPasswordValidity: Duration.hours(24),  // Von 3 Tagen reduziert
      },

      // Umfassende Benutzerattribute für RBAC
      standardAttributes: {
        email: { required: true, mutable: false },
        givenName: { required: true, mutable: true },
        familyName: { required: true, mutable: true },
      },
      customAttributes: {
        // Rollenbasierte Zugriffskontrolle
        role: new StringAttribute({ mutable: true }),
        department: new StringAttribute({ mutable: true }),
        accessLevel: new StringAttribute({ mutable: true }),
        // Audit-Trail-Attribute
        lastLoginDate: new StringAttribute({ mutable: true }),
        createdBy: new StringAttribute({ mutable: false }),
        // Compliance-Attribute
        dataAccessLevel: new StringAttribute({ mutable: true }),
        complianceFlags: new StringAttribute({ mutable: true }),
      },

      // Enterprise-Sicherheitseinstellungen
      accountRecovery: AccountRecovery.EMAIL_ONLY,
      mfa: props.stage === 'prod' ? Mfa.REQUIRED : Mfa.OPTIONAL,
      mfaSecondFactor: {
        sms: false,  // Nur TOTP für Sicherheit
        otp: true,
      },

      // Erweiterte Bedrohungsschutz
      advancedSecurityMode: props.stage === 'prod'
        ? AdvancedSecurityMode.ENFORCED
        : AdvancedSecurityMode.AUDIT,

      // E-Mail-Konfiguration für Marken-Kommunikation
      emailSettings: {
        from: 'noreply@yourcompany.com',
        replyTo: 'support@yourcompany.com',
      },

      // Geräteverfolgung für Sicherheit
      deviceTracking: {
        challengeRequiredOnNewDevice: true,
        deviceOnlyRememberedOnUserPrompt: false,
      },

      // Datenschutz
      removalPolicy: props.stage === 'prod' ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY,
      deletionProtection: props.stage === 'prod',
    });

    // Enterprise Lambda-Trigger hinzufügen
    this.addSecurityTriggers(props.stage);

    // Produktions-App-Client erstellen
    this.userPoolClient = new UserPoolClient(this, 'EnterpriseClient', {
      userPool: this.userPool,
      userPoolClientName: `my-service-${props.stage}-client-v2`,

      // Erlaubte Authentifizierungsflows
      authFlows: {
        userPassword: false,  // Weniger sicheren Flow deaktivieren
        userSrp: true,       // Secure Remote Password-Protokoll
        custom: true,        // Benutzerdefinierte Auth-Challenges
        adminUserPassword: props.stage !== 'prod',  // Admin-Flow nur in Nicht-Prod
      },

      // OAuth-Konfiguration für Enterprise-SSO
      oAuth: {
        flows: {
          authorizationCodeGrant: true,
          implicitCodeGrant: false,  // Implicit Flow für Sicherheit deaktivieren
          clientCredentials: false,
        },
        scopes: [
          OAuthScope.EMAIL,
          OAuthScope.OPENID,
          OAuthScope.PROFILE,
          OAuthScope.custom('read:profile'),
          OAuthScope.custom('write:profile'),
        ],
        callbackUrls: props.callbackUrls || [],
        logoutUrls: [`https://${props.stage === 'prod' ? 'app' : props.stage}.yourcompany.com/logout`],
      },

      generateSecret: false,  // Öffentlicher Client für SPA

      // Feinabgestimmter Attributzugriff
      readAttributes: new ClientAttributes()
        .withStandardAttributes({
          email: true,
          emailVerified: true,
          givenName: true,
          familyName: true,
        })
        .withCustomAttributes('role', 'department', 'accessLevel'),

      writeAttributes: new ClientAttributes()
        .withCustomAttributes('lastLoginDate'),  // Begrenzter Schreibzugriff

      // Sicherheitsfokussierte Token-Einstellungen
      idTokenValidity: Duration.minutes(30),     // Kurzlebig für Sicherheit
      accessTokenValidity: Duration.minutes(30), // Kurzlebig für Sicherheit
      refreshTokenValidity: Duration.days(1),    // Tägliche Neauthentifizierung

      // Erweiterte Sicherheitsoptionen
      preventUserExistenceErrors: true,
      enableTokenRevocation: true,

      // Benutzerdefinierte Token-Einstellungen
      authSessionValidity: Duration.minutes(3),  // Schneller Auth-Flow-Timeout
    });

    // API Gateway-Authorizer erstellen
    this.authorizer = new CognitoUserPoolsAuthorizer(this, 'CognitoAuthorizer', {
      cognitoUserPools: [this.userPool],
      authorizerName: `${props.api.restApiName}-cognito-auth`,
      identitySource: 'method.request.header.Authorization',
      resultsCacheTtl: Duration.minutes(5),  // Cache für Performance
    });

    // Benutzerdefinierte Domain für Markenerlebnis hinzufügen
    if (props.domainPrefix) {
      new UserPoolDomain(this, 'UserPoolDomain', {
        userPool: this.userPool,
        cognitoDomainPrefix: `${props.domainPrefix}-${props.stage}`,
      });
    }

    // Produktions-Monitoring und -Alarmierung
    this.addProductionMonitoring(props.stage);

    // Compliance-Tagging
    Tags.of(this).add('DataClassification', 'PII');
    Tags.of(this).add('Compliance', 'SOC2-GDPR');
    Tags.of(this).add('Service', 'authentication');
    Tags.of(this).add('Stage', props.stage);
  }
}

Die 400ms-Autorisierungs-Katastrophe#

Unser Legacy-Autorisierungs-Setup tötete die Performance. Jede API-Anfrage benötigte:

  1. JWT-Dekodierung: 50ms
  2. Cognito JWK-Abruf: 150ms (kein Caching)
  3. Signaturverifikation: 80ms
  4. Datenbankrollen-Lookup: 120ms
  5. Gesamte Autorisierungszeit: 400ms pro Anfrage

Geschäftsauswirkung: 28% der Gesamtanfrage-Zeit wurde für Autorisierung aufgewendet. Mobile App wurde als "langsam" empfunden. Kundenbeschwerden über API-Reaktionsfähigkeit.

Hochleistungs-JWT-Autorisierung#

Hier ist der caching-optimierte Authorizer, der die Latenz von 400ms auf 12ms reduzierte:

TypeScript
// lib/constructs/auth/high-performance-jwt-authorizer.ts
import {
  TokenAuthorizer,
  IdentitySource,
  IRestApi
} from 'aws-cdk-lib/aws-apigateway';
import { Duration } from 'aws-cdk-lib';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';

export class HighPerformanceJwtAuthorizer extends TokenAuthorizer {
  constructor(scope: Construct, id: string, props: {
    api: IRestApi;
    userPoolId: string;
    region: string;
    stage: string;
  }) {
    // Optimierte Authorizer-Funktion für Produktion
    const authorizerFunction = new NodejsFunction(scope, 'OptimizedAuthorizerFunction', {
      entry: 'src/auth/production-jwt-authorizer.ts',
      handler: 'handler',
      // Provisioned Concurrency für konsistente Performance
      reservedConcurrentExecutions: props.stage === 'prod' ? 10 : undefined,
      timeout: Duration.seconds(5),  // Schneller Timeout für schnelle Fehler
      memorySize: 512,  // Für JWT-Verarbeitung optimiert
      logRetention: RetentionDays.ONE_MONTH,
      environment: {
        USER_POOL_ID: props.userPoolId,
        REGION: props.region,
        STAGE: props.stage,
        // Performance-Optimierungs-Flags
        ENABLE_METRICS: props.stage === 'prod' ? 'true' : 'false',
        CACHE_TIMEOUT_MS: '300000',  // 5 Minuten
      },
      bundling: {
        // Bundle-Größe für schnellere Cold Starts minimieren
        minify: true,
        target: 'node20',
        // Nur wesentliche Dependencies einschließen
        nodeModules: ['jsonwebtoken', 'jwk-to-pem'],
        externalModules: ['@aws-sdk/*'],
      },
    });

    super(scope, id, {
      restApi: props.api,
      handler: authorizerFunction,
      identitySource: IdentitySource.header('Authorization'),
      // Aggressives Caching für Performance
      resultsCacheTtl: Duration.minutes(5),
      authorizerName: `${props.api.restApiName}-jwt-authorizer-v2`,
      // Strenge Token-Validierung
      validationRegex: '^Bearer [A-Za-z0-9\\-_=]+\\.[A-Za-z0-9\\-_=]+\\.[A-Za-z0-9\\-_.+/=]*,
    });
  }
}

Sicherheits-Migrationsergebnisse#

Nach 3 Wochen intensiver Sicherheits-Neuerstellung sind hier die messbaren Verbesserungen:

Performance-Verbesserungen#

  • Autorisierungslatenz: 400ms → 12ms (97% Reduktion)
  • Cache-Hit-Rate: 0% → 94% (JWK-Caching)
  • API-Antwortzeit: 1,4s → 0,8s Durchschnitt (42% Verbesserung)
  • Mobile App wahrgenommene Performance: "Langsam" → "Schnell" Benutzerfeedback

Sicherheitslage#

  • Überprivilegierte Funktionen: 47 → 0 (100% Eliminierung)
  • Wildcard-IAM-Berechtigungen: 23 Funktionen → 0 Funktionen
  • Audit-Trail-Abdeckung: 0% → 100% (alle Auth-Events protokolliert)
  • Fehlgeschlagene Auth-Erkennung: Manuell → 30-Sekunden automatisierte Alarme
  • Compliance-Status: Fehlgeschlagenes Audit → SOC 2 Type II konform

Betriebseffizienz#

  • Auth-Troubleshooting-Zeit: 3 Stunden/Woche → 15 Minuten/Woche
  • Sicherheitsvorfälle: 2-3/Monat → 0/Monat (6 Monate laufend)
  • Autorisierungs-Cache-Hit-Rate: 94% (5-Minuten-TTL)
  • JWT-Validierungsfehler: 15/Tag → 2/Tag (bessere Fehlerbehandlung)

Geschäftsauswirkung#

  • Enterprise-Deals freigegeben: $2,3M Verkaufspipeline wiedereröffnet
  • Compliance-Audit: SOC 2 Type II bestanden
  • GDPR-Strafenrisiko: $180K → $0 (vollständige Compliance)
  • Kundenvertrauen: Sichtbare Sicherheitsverbesserungen in Verkaufsdemos

Hart erlernte Sicherheitslektionen#

1. Beginnen Sie immer mit Least Privilege#

Vorher: "Action": "*" weil "es schneller zu shippen ist" Nachher: Explizite Berechtigungen für jede Funktion, jede Ressource Auswirkung: 94% Reduktion der Angriffsfläche

2. Performance und Sicherheit schließen sich nicht gegenseitig aus#

Vorher: "Sicherheit fügt Latenz hinzu" Nachher: Ordnungsgemäßes Caching machte Auth schneller UND sicherer Auswirkung: 97% Latenzreduktion mit stärkerer Sicherheit

3. Audit Trail ist nicht verhandelbar#

Vorher: Null Sichtbarkeit, wer auf was zugriff Nachher: Jede Auth-Entscheidung mit vollem Kontext protokolliert Auswirkung: SOC 2-Audit bestanden, Compliance ermöglicht

4. Cachen Sie alles (sicher)#

Vorher: JWK-Abruf bei jeder Anfrage Nachher: Mehrstufiges Caching mit Invalidierung Auswirkung: 94% Cache-Hit-Rate, unter 20ms Auth

5. Rollenbasierte Zugriffskontrolle skaliert#

Vorher: Ad-hoc-Berechtigungen pro Funktion Nachher: Standardisierte Rollen mit klaren Verantwortlichkeiten Auswirkung: Vereinfachte Verwaltung, bessere Sicherheit

Was kommt als Nächstes#

Ihre Serverless-Anwendung hat jetzt Enterprise-Grade-Authentifizierung und -Autorisierung, die tatsächlich performt. Benutzerverwaltung ist kugelsicher, APIs sind durch optimierte JWT-Verifikation geschützt und IAM-Richtlinien folgen strengen Least-Privilege-Prinzipien.

In Teil 6 werden wir die gesamte Migration zusammenführen:

  • Vollständige Migrationsstrategien und Zeitpläne
  • Testansätze, die tatsächlich in der Produktion funktionieren
  • Rollback-Verfahren, die Ihre Karriere retten
  • Performance-Optimierung über den gesamten Stack
  • Monitoring und Observability, die Vorfälle verhindern

Die Sicherheitsgrundlage ist solide. Lassen Sie uns diese Migration ordnungsgemäß abschließen.

API Key Management#

Übersetzung folgt.

Migration Security Checklist#

Übersetzung folgt.

Security Migration Results#

Übersetzung folgt.

Hard-Learned Security Lessons#

Übersetzung folgt.

What's Next#

Übersetzung folgt.

Loading...

Kommentare (0)

An der Unterhaltung teilnehmen

Melde dich an, um deine Gedanken zu teilen und mit der Community zu interagieren

Noch keine Kommentare

Sei der erste, der deine Gedanken zu diesem Beitrag teilt!

Related Posts