Header menu logo FsCDK

KMS AWS Key Management Service (KMS): Cryptographic Excellence with FsCDK

AWS Key Management Service (KMS) provides secure key management. As AWS cryptographer Colm MacCárthaigh advises: "Encryption is table stakes—do it right with KMS." This portal enhances docs with hero insights, checklists, drills, and rated resources (4.5+).

What is KMS?

AWS Key Management Service (KMS) is a managed service that makes it easy to create and control cryptographic keys used to protect your data. KMS keys are used to encrypt data at rest across many AWS services.

#r "../src/bin/Release/net8.0/publish/Amazon.JSII.Runtime.dll"
#r "../src/bin/Release/net8.0/publish/Constructs.dll"
#r "../src/bin/Release/net8.0/publish/Amazon.CDK.Lib.dll"
#r "../src/bin/Release/net8.0/publish/System.Text.Json.dll"
#r "../src/bin/Release/net8.0/publish/FsCDK.dll"

open Amazon.CDK
open Amazon.CDK.AWS.KMS
open Amazon.CDK.AWS.S3
open Amazon.CDK.AWS.SecretsManager
open FsCDK

Use Cases

S3 Bucket Encryption

stack "S3EncryptionStack" {
    description "S3 bucket with KMS encryption"

    // Create KMS key for S3
    let! s3Key =
        kmsKey "s3-encryption-key" {
            description "KMS key for S3 bucket encryption"
            alias "alias/s3-data-encryption"
            enableKeyRotation
        }

    // Create S3 bucket with KMS encryption
    let encryptedBucket =
        s3Bucket "encrypted-data-bucket" {
            encryption BucketEncryption.KMS
            encryptionKey s3Key
            versioned true
        }

    ()
}

Secrets Manager Encryption

stack "SecretsEncryptionStack" {
    description "Secrets Manager with custom KMS key"

    // Create KMS key for secrets
    let! secretsKey =
        kmsKey "secrets-encryption-key" {
            description "KMS key for Secrets Manager"
            alias "alias/secrets-encryption"
            enableKeyRotation
        }

    // Create secret with KMS encryption
    let apiSecret =
        secret "api-credentials" {
            description "API credentials for external service"
            encryptionKey secretsKey
            generateSecretString (SecretsManagerHelpers.generatePassword 32 None)
        }

    ()
}

Lambda Environment Variables

stack "LambdaEncryptionStack" {
    description "Lambda with encrypted environment variables"

    // Create KMS key for Lambda
    let! lambdaKey =
        kmsKey "lambda-env-key" {
            description "Encrypts Lambda environment variables"
            alias "alias/lambda-env-encryption"
            enableKeyRotation
        }

    // Create Lambda with encrypted env vars
    let myFunction =
        lambda "my-secure-function" {
            handler "index.handler"
            runtime Amazon.CDK.AWS.Lambda.Runtime.NODEJS_18_X
            code "./lambda-code"

            environment [ "API_KEY", "super-secret-key"; "DATABASE_URL", "postgres://..." ]

            environmentEncryption lambdaKey
        }

    ()
}

Asymmetric Keys for Signing

stack "SigningKeyStack" {
    description "Asymmetric KMS key for digital signatures"

    // Create a signing key
    let signingKey =
        kmsKey "code-signing-key" {
            description "Signs application artifacts"
            alias "alias/code-signing"
            keySpec KeySpec.RSA_2048
            keyUsage KeyUsage.SIGN_VERIFY
            disableKeyRotation // Asymmetric keys don't support automatic rotation
        }

    ()
}

Complete Production Example

stack "ProductionKMSStack" {
    env (
        environment {
            account config.Account
            region config.Region
        }
    )

    description "Production KMS keys for multi-tier application"
    tags [ "Environment", "Production"; "ManagedBy", "FsCDK" ]

    // Application data encryption key
    let! appDataKey =
        kmsKey "app-data-key" {
            description "Encrypts application data at rest"
            alias "alias/prod-app-data"
            enableKeyRotation
            pendingWindow (Duration.Days(30.0))
        }

    // Database encryption key
    let dbKey =
        kmsKey "database-key" {
            description "Encrypts RDS database"
            alias "alias/prod-database"
            enableKeyRotation
        }

    // Secrets encryption key
    let secretsKey =
        kmsKey "secrets-key" {
            description "Encrypts secrets and credentials"
            alias "alias/prod-secrets"
            enableKeyRotation
        }

    // S3 bucket with custom KMS key
    let dataBucket =
        s3Bucket "production-data" {
            encryption BucketEncryption.KMS
            encryptionKey appDataKey
            versioned true
        }

    // CloudWatch alarm for key usage
    cloudwatchAlarm "kms-key-usage-alarm" {
        description "Alert on unusual KMS key usage"
        metricNamespace "AWS/KMS"
        metricName "NumberOfOperations"
        dimensions [ "KeyId", appDataKey.KeyId ]
        statistic "Sum"
        threshold 1000.0
        evaluationPeriods 1
        period (Duration.Minutes(5.0))
    }

    ()
}

Best Practices: Hero-Guided

From MacCárthaigh's crypto talks.

Rotation & Separation

Rotate annually; isolate keys by env.

Least Privilege

Separate encrypt/decrypt grants.

Monitoring

Log all ops with CloudTrail.

Operational Checklist

  1. Enable rotation.
  2. Grant minimal IAM.
  3. Monitor usage alarms.
  4. Test envelope encryption.

Practice Drills

Drill 1: Key Creation

  1. Create rotating key.
  2. Encrypt/decrypt data.
  3. Test rotation.

Drill 2: Integration

  1. Encrypt S3 bucket.
  2. Verify access logs.

Further Learning

namespace Amazon
namespace Amazon.CDK
namespace Amazon.CDK.AWS
namespace Amazon.CDK.AWS.KMS
namespace Amazon.CDK.AWS.S3
namespace Amazon.CDK.AWS.SecretsManager
namespace FsCDK
val get: unit -> {| Account: string; Region: string |}
namespace System
type Environment = static member Exit: exitCode: int -> unit static member ExpandEnvironmentVariables: name: string -> string static member FailFast: message: string -> unit + 1 overload static member GetCommandLineArgs: unit -> string array static member GetEnvironmentVariable: variable: string -> string + 1 overload static member GetEnvironmentVariables: unit -> IDictionary + 1 overload static member GetFolderPath: folder: SpecialFolder -> string + 1 overload static member GetLogicalDrives: unit -> string array static member SetEnvironmentVariable: variable: string * value: string -> unit + 1 overload static member CommandLine: string ...
<summary>Provides information about, and means to manipulate, the current environment and platform. This class cannot be inherited.</summary>
System.Environment.GetEnvironmentVariable(variable: string) : string
System.Environment.GetEnvironmentVariable(variable: string, target: System.EnvironmentVariableTarget) : string
val config: {| Account: string; Region: string |}
module Config from Kms-encryption
val stack: name: string -> StackBuilder
<summary>Creates an AWS CDK Stack construct.</summary>
<param name="name">The name of the stack.</param>
<code lang="fsharp"> stack "MyStack" { lambda myFunction bucket myBucket } </code>
custom operation: description (string) Calls StackBuilder.Description
<summary>Sets the stack description.</summary>
<param name="config">The current stack configuration.</param>
<param name="desc">A description of the stack.</param>
<code lang="fsharp"> stack "MyStack" { description "My application stack" } </code>
val myKey: KMSKeySpec
val kmsKey: name: string -> KMSKeyBuilder
<summary> Creates a new KMS key builder with secure defaults. Example: kmsKey "my-encryption-key" { description "Encrypts sensitive data" } </summary>
custom operation: description (string) Calls KMSKeyBuilder.Description
<summary>Sets the description for the KMS key.</summary>
<param name="description">Human-readable description.</param>
<code lang="fsharp"> kmsKey "my-key" { description "Encryption key for S3 bucket data" } </code>
custom operation: alias (string) Calls KMSKeyBuilder.Alias
<summary>Sets an alias for the KMS key (e.g., "alias/my-app-key").</summary>
<param name="alias">The key alias.</param>
<code lang="fsharp"> kmsKey "my-key" { alias "alias/my-app-key" } </code>
custom operation: enableKeyRotation Calls KMSKeyBuilder.EnableKeyRotation
<summary>Enables automatic key rotation (recommended for security).</summary>
<code lang="fsharp"> kmsKey "my-key" { enableKeyRotation } </code>
val s3Key: IKey
val encryptedBucket: BucketSpec
val s3Bucket: name: string -> BucketBuilder
<summary> Creates a new S3 bucket builder with secure defaults. Example: s3Bucket "my-bucket" { versioned true } Alias for bucket builder. </summary>
custom operation: encryption (BucketEncryption) Calls BucketBuilder.Encryption
[<Struct>] type BucketEncryption = | UNENCRYPTED = 0 | KMS_MANAGED = 1 | S3_MANAGED = 2 | KMS = 3 | DSSE_MANAGED = 4 | DSSE = 5
field BucketEncryption.KMS: BucketEncryption = 3
custom operation: encryptionKey (IKey) Calls BucketBuilder.EncryptionKey
custom operation: versioned (bool) Calls BucketBuilder.Versioned
<summary> Enables or disables versioning for the S3 bucket. **Security Best Practice:** Enable versioning for: - Critical data that requires audit trails - Data subject to compliance requirements (HIPAA, SOC2, etc.) - Production buckets storing business data **Cost Consideration:** Versioning stores all versions of objects, increasing storage costs. Only disable for: - Temporary/cache buckets - Build artifacts with short lifecycle - Development/testing buckets **Default:** false (opt-in for cost optimization) </summary>
<param name="value">True to enable versioning, false to disable.</param>
<param name="config">The current bucket configuration.</param>
<code lang="fsharp"> bucket "production-data" { versioned true // Enable for production } bucket "cache-bucket" { versioned false // Disable for temp data } </code>
val secretsKey: IKey
val apiSecret: SecretsManagerSpec
val secret: name: string -> SecretsManagerBuilder
<summary> Creates a new Secrets Manager secret builder with secure defaults. Example: secret "my-api-key" { description "API key for external service" } </summary>
custom operation: description (string) Calls SecretsManagerBuilder.Description
custom operation: encryptionKey (IKey) Calls SecretsManagerBuilder.EncryptionKey
custom operation: generateSecretString (SecretStringGenerator) Calls SecretsManagerBuilder.GenerateSecretString
module SecretsManagerHelpers from FsCDK
<summary> Helper functions for creating secret string generators </summary>
val generatePassword: length: int -> excludeCharacters: string option -> SecretStringGenerator
<summary> Creates a secret string generator for a random password </summary>
union case Option.None: Option<'T>
val lambdaKey: IKey
val myFunction: FunctionSpec
val lambda: name: string -> FunctionBuilder
<summary>Creates a Lambda function configuration.</summary>
<param name="name">The function name.</param>
<code lang="fsharp"> lambda "MyFunction" { handler "index.handler" runtime Runtime.NODEJS_18_X code "./lambda" timeout 30.0 } </code>
custom operation: handler (string) Calls FunctionBuilder.Handler
<summary>Sets the handler for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="handler">The handler name (e.g., "index.handler").</param>
<code lang="fsharp"> lambda "MyFunction" { handler "index.handler" } </code>
custom operation: runtime (AWS.Lambda.Runtime) Calls FunctionBuilder.Runtime
<summary>Sets the runtime for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="runtime">The Lambda runtime.</param>
<code lang="fsharp"> lambda "MyFunction" { runtime Runtime.NODEJS_18_X } </code>
namespace Amazon.CDK.AWS.Lambda
Multiple items
type Runtime = inherit DeputyBase new: name: string * ?family: Nullable<RuntimeFamily> * ?props: ILambdaRuntimeProps -> unit member RuntimeEquals: other: Runtime -> bool member ToString: unit -> string member BundlingImage: DockerImage member Family: Nullable<RuntimeFamily> member IsVariable: bool member Name: string member SupportsCodeGuruProfiling: bool member SupportsInlineCode: bool ...

--------------------
AWS.Lambda.Runtime(name: string, ?family: System.Nullable<AWS.Lambda.RuntimeFamily>, ?props: AWS.Lambda.ILambdaRuntimeProps) : AWS.Lambda.Runtime
property AWS.Lambda.Runtime.NODEJS_18_X: AWS.Lambda.Runtime with get
custom operation: code (AWS.Lambda.Code) Calls FunctionBuilder.Code
<summary>Sets the code source from a Code object.</summary>
<param name="config">The function configuration.</param>
<param name="path">The Code object.</param>
<code lang="fsharp"> lambda "MyFunction" { code (Code.FromBucket myBucket "lambda.zip") } </code>
custom operation: environment ((string * string) list) Calls FunctionBuilder.Environment
<summary>Sets environment variables for the Lambda function.</summary>
<param name="config">The function configuration.</param>
<param name="env">List of key-value pairs for environment variables.</param>
<code lang="fsharp"> lambda "MyFunction" { environment [ "KEY1", "value1"; "KEY2", "value2" ] } </code>
custom operation: environmentEncryption (IKey) Calls FunctionBuilder.EnvironmentEncryption
<summary>Sets a KMS key to encrypt environment variables.</summary>
<param name="config">The function configuration.</param>
<param name="key">KMS key for environment encryption.</param>
<code lang="fsharp"> lambda "MyFunction" { environmentEncryption myKmsKey } </code>
val signingKey: KMSKeySpec
custom operation: keySpec (KeySpec) Calls KMSKeyBuilder.KeySpec
<summary>Sets the key spec (SYMMETRIC_DEFAULT, RSA_2048, etc.).</summary>
<param name="spec">The key specification.</param>
<code lang="fsharp"> kmsKey "my-key" { keySpec KeySpec.RSA_2048 } </code>
[<Struct>] type KeySpec = | SYMMETRIC_DEFAULT = 0 | RSA_2048 = 1 | RSA_3072 = 2 | RSA_4096 = 3 | ECC_NIST_P256 = 4 | ECC_NIST_P384 = 5 | ECC_NIST_P521 = 6 | ECC_SECG_P256K1 = 7 | HMAC_224 = 8 | HMAC_256 = 9 ...
field KeySpec.RSA_2048: KeySpec = 1
custom operation: keyUsage (KeyUsage) Calls KMSKeyBuilder.KeyUsage
<summary>Sets the key usage (ENCRYPT_DECRYPT, SIGN_VERIFY, GENERATE_VERIFY_MAC).</summary>
<param name="usage">The key usage.</param>
<code lang="fsharp"> kmsKey "my-key" { keyUsage KeyUsage.SIGN_VERIFY } </code>
[<Struct>] type KeyUsage = | ENCRYPT_DECRYPT = 0 | SIGN_VERIFY = 1 | GENERATE_VERIFY_MAC = 2 | KEY_AGREEMENT = 3
field KeyUsage.SIGN_VERIFY: KeyUsage = 1
custom operation: disableKeyRotation Calls KMSKeyBuilder.DisableKeyRotation
<summary>Disables automatic key rotation (not recommended).</summary>
<code lang="fsharp"> kmsKey "my-key" { disableKeyRotation } </code>
custom operation: env (IEnvironment) Calls StackBuilder.Env
val environment: EnvironmentBuilder
<summary>Creates an AWS CDK Environment configuration.</summary>
<code lang="fsharp"> environment { account "123456789012" region "us-west-2" } </code>
custom operation: account (string) Calls EnvironmentBuilder.Account
<summary>Sets the AWS account ID for the environment.</summary>
<param name="config">The current configuration.</param>
<param name="accountId">The AWS account ID.</param>
<code lang="fsharp"> environment { account "123456789012" } </code>
anonymous record field Account: string
custom operation: region (string) Calls EnvironmentBuilder.Region
<summary>Sets the AWS region for the environment.</summary>
<param name="config">The current configuration.</param>
<param name="regionName">The AWS region name.</param>
<code lang="fsharp"> environment { region "us-west-2" } </code>
anonymous record field Region: string
custom operation: tags ((string * string) list) Calls StackBuilder.Tags
<summary>Adds tags to the stack.</summary>
<param name="config">The current stack configuration.</param>
<param name="tags">A list of key-value pairs for tagging.</param>
<code lang="fsharp"> stack "MyStack" { tags [ "Environment", "Production"; "Team", "DevOps" ] } </code>
val appDataKey: IKey
custom operation: pendingWindow (Duration) Calls KMSKeyBuilder.PendingWindow
<summary>Sets the pending window for key deletion (7-30 days).</summary>
<param name="window">The pending window duration.</param>
<code lang="fsharp"> kmsKey "my-key" { pendingWindow (Duration.Days(30.0)) } </code>
type Duration = inherit DeputyBase member FormatTokenToNumber: unit -> string member IsUnresolved: unit -> bool member Minus: rhs: Duration -> Duration member Plus: rhs: Duration -> Duration member ToDays: ?opts: ITimeConversionOptions -> float member ToHours: ?opts: ITimeConversionOptions -> float member ToHumanString: unit -> string member ToIsoString: unit -> string member ToMilliseconds: ?opts: ITimeConversionOptions -> float ...
Duration.Days(amount: float) : Duration
val dbKey: KMSKeySpec
val secretsKey: KMSKeySpec
val dataBucket: BucketSpec
val cloudwatchAlarm: name: string -> CloudWatchAlarmBuilder
custom operation: description (string) Calls CloudWatchAlarmBuilder.Description
<summary>Sets the alarm description.</summary>
custom operation: metricNamespace (string) Calls CloudWatchAlarmBuilder.MetricNamespace
<summary>Sets the CloudWatch metric namespace (e.g., "AWS/Lambda", "AWS/RDS").</summary>
custom operation: metricName (string) Calls CloudWatchAlarmBuilder.MetricName
<summary>Sets the metric name (e.g., "Errors", "CPUUtilization").</summary>
custom operation: dimensions ((string * string) list) Calls CloudWatchAlarmBuilder.Dimensions
<summary>Sets the metric dimensions for filtering (e.g., FunctionName, DBInstanceIdentifier).</summary>
property IKey.KeyId: string with get
custom operation: statistic (string) Calls CloudWatchAlarmBuilder.Statistic
<summary>Sets the statistic (Average, Sum, Minimum, Maximum, SampleCount).</summary>
custom operation: threshold (float) Calls CloudWatchAlarmBuilder.Threshold
<summary>Sets the alarm threshold value.</summary>
custom operation: evaluationPeriods (int) Calls CloudWatchAlarmBuilder.EvaluationPeriods
<summary>Sets the number of periods to evaluate.</summary>
custom operation: period (Duration) Calls CloudWatchAlarmBuilder.Period
<summary>Sets the evaluation period.</summary>
Duration.Minutes(amount: float) : Duration

Type something to start searching.