cryptography

Implementing Envelope Encryption with AWS KMS

Envelope encryption is a strategy where data is encrypted with a data encryption key (DEK), and the DEK itself is encrypted with a master key (KEK) managed by AWS KMS. This approach allows encrypting large volumes of data locally while keeping the master key secure in a hardware security module (HSM) managed by AWS. This skill covers implementing envelope encryption using AWS KMS GenerateDataKey API.

awscryptographyencryptionenvelope-encryptionkey-managementkms
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Envelope encryption is a strategy where data is encrypted with a data encryption key (DEK), and the DEK itself is encrypted with a master key (KEK) managed by AWS KMS. This approach allows encrypting large volumes of data locally while keeping the master key secure in a hardware security module (HSM) managed by AWS. This skill covers implementing envelope encryption using AWS KMS GenerateDataKey API.

When to Use

  • When deploying or configuring implementing envelope encryption with aws kms capabilities in your environment
  • When establishing security controls aligned to compliance requirements
  • When building or improving security architecture for this domain
  • When conducting security assessments that require this implementation

Prerequisites

  • Familiarity with cryptography concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

Objectives

  • Understand the envelope encryption pattern and its advantages
  • Generate data encryption keys using AWS KMS GenerateDataKey
  • Encrypt/decrypt data locally using DEKs
  • Store encrypted DEK alongside ciphertext
  • Implement key caching to reduce KMS API calls
  • Handle key rotation with automatic re-encryption
  • Implement multi-region encryption for disaster recovery

Key Concepts

Envelope Encryption Flow

  1. Call kms:GenerateDataKey to get plaintext DEK + encrypted DEK
  2. Use plaintext DEK to encrypt data locally (AES-256-GCM)
  3. Store encrypted DEK alongside ciphertext
  4. Discard plaintext DEK from memory
  5. For decryption: call kms:Decrypt on encrypted DEK, then decrypt data

Advantages Over Direct KMS Encryption

Aspect Direct KMS Envelope Encryption
Max data size 4 KB Unlimited
Latency Network round-trip per operation Local encryption
Cost $0.03/10,000 requests Fewer KMS requests
Offline Not possible Yes (with cached DEKs)

KMS Key Types

  • AWS Managed: AWS creates and manages (aws/s3, aws/ebs)
  • Customer Managed: You create and manage policies
  • Custom Key Store: Backed by CloudHSM cluster

Security Considerations

  • Never store plaintext DEK; only keep encrypted DEK
  • Use key policies to restrict who can call GenerateDataKey and Decrypt
  • Enable AWS CloudTrail logging for all KMS API calls
  • Implement key rotation (automatic annual rotation for CMKs)
  • Use encryption context for authenticated encryption metadata
  • Handle KMS throttling with exponential backoff

Validation Criteria

  • GenerateDataKey returns plaintext and encrypted DEK
  • Data encrypts correctly with plaintext DEK using AES-256-GCM
  • Encrypted DEK can be decrypted via KMS Decrypt API
  • Decrypted DEK recovers the original data
  • Plaintext DEK is wiped from memory after use
  • Encryption context is validated during decryption
  • Key rotation re-encrypts DEKs with new master key
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.9 KB

API Reference — Implementing Envelope Encryption with AWS KMS

Libraries Used

  • boto3: AWS SDK for KMS key management and data key generation
  • cryptography: AES-256-GCM for local data encryption with generated data keys

CLI Interface

python agent.py --region us-east-1 encrypt --input <file> --output <out> --key-id <kms_key>
python agent.py --region us-east-1 decrypt --input <encrypted> --output <out>
python agent.py --region us-east-1 list-keys
python agent.py --region us-east-1 audit --key-id <kms_key>

Core Functions

generate_data_key(kms_key_id, region)

Generates a data encryption key (DEK) using AWS KMS.

  • kms.generate_data_key(KeyId=key_id, KeySpec="AES_256")
  • Returns plaintext key (for local encryption) and encrypted key (for storage).

encrypt_data(plaintext_bytes, kms_key_id, region)

Performs envelope encryption: generates DEK via KMS, encrypts data locally with AES-256-GCM, stores encrypted DEK alongside ciphertext.

decrypt_data(envelope, region)

Decrypts envelope: calls kms.decrypt(CiphertextBlob=encrypted_key) to recover DEK, then decrypts data locally.

list_kms_keys(region)

Lists KMS keys with metadata using kms.list_keys() and kms.describe_key().

audit_key_policy(key_id, region)

Audits KMS key policy for overly permissive principals (Principal: "*").

  • kms.get_key_policy(KeyId=key_id, PolicyName="default")

boto3 KMS API Calls

Method Purpose
kms.generate_data_key(KeyId, KeySpec) Generate plaintext + encrypted DEK
kms.decrypt(CiphertextBlob) Decrypt encrypted DEK back to plaintext
kms.list_keys() List all KMS keys in the account
kms.describe_key(KeyId) Get key metadata (state, usage, origin)
kms.get_key_policy(KeyId, PolicyName) Get key resource policy JSON

Dependencies

pip install boto3>=1.28 cryptography>=41.0
standards.md1.9 KB

Standards and References - Envelope Encryption with AWS KMS

AWS Documentation

AWS KMS Developer Guide

AWS KMS API Reference

AWS Encryption SDK

Cryptographic Standards

NIST SP 800-57 Part 1 - Key Management

NIST SP 800-38F - Key Wrap

FIPS 140-2 Level 2 (KMS HSMs)

  • Description: KMS HSMs are validated at FIPS 140-2 Level 2 (Level 3 for CloudHSM)

Compliance Frameworks

PCI DSS v4.0 Requirement 3

  • Key management with separation of DEK and KEK
  • KMS satisfies key management requirements

SOC 2 Type II

  • AWS KMS is SOC 2 compliant
  • Encryption controls map to CC6.1 (logical access controls)

HIPAA

  • KMS encryption satisfies encryption requirements for ePHI
  • BAA required with AWS

Python Libraries

boto3 (AWS SDK for Python)

aws-encryption-sdk

workflows.md1.5 KB

Workflows - Envelope Encryption with AWS KMS

Workflow 1: Encrypt Data with Envelope Encryption

[Application]
      |
[Call KMS GenerateDataKey]
(KeyId=CMK ARN, KeySpec=AES_256)
      |
[KMS Returns]:
  - Plaintext DEK (32 bytes)
  - Encrypted DEK (ciphertext blob)
      |
[Encrypt Data Locally]
(AES-256-GCM with plaintext DEK)
      |
[Store]:
  - Encrypted DEK (ciphertext blob)
  - Encrypted data (nonce + ciphertext + tag)
  - Encryption context metadata
      |
[Wipe Plaintext DEK from Memory]

Workflow 2: Decrypt Data

[Read Stored Data]
  - Encrypted DEK
  - Encrypted data
  - Encryption context
      |
[Call KMS Decrypt]
(CiphertextBlob=Encrypted DEK, EncryptionContext)
      |
[KMS Returns Plaintext DEK]
      |
[Decrypt Data Locally]
(AES-256-GCM with plaintext DEK)
      |
[Return Plaintext Data]
      |
[Wipe Plaintext DEK from Memory]

Workflow 3: Key Rotation

[Enable Automatic Key Rotation on CMK]
(KMS rotates backing key annually)
      |
[New GenerateDataKey calls use new backing key]
      |
[Old encrypted DEKs still decrypt]
(KMS tracks all backing key versions)
      |
[Optional: Re-encrypt old DEKs]
[Call KMS ReEncrypt to update DEK encryption]

Workflow 4: Multi-Region Encryption

[Primary Region (us-east-1)]
  |
  [Create Multi-Region CMK]
  [Replicate to us-west-2, eu-west-1]
  |
  [Encrypt with Regional Endpoint]
  |
[Secondary Region (us-west-2)]
  |
  [Same Key ID works for Decrypt]
  [No cross-region API calls needed]

Scripts 2

agent.py5.9 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for implementing envelope encryption using AWS KMS."""

import json
import argparse
import os
import base64

try:
    import boto3
    from botocore.exceptions import ClientError
except ImportError:
    boto3 = None

try:
    from cryptography.hazmat.primitives.ciphers.aead import AESGCM
except ImportError:
    AESGCM = None

NONCE_SIZE = 12


def generate_data_key(kms_key_id, region="us-east-1"):
    """Generate a data encryption key using AWS KMS."""
    kms = boto3.client("kms", region_name=region)
    resp = kms.generate_data_key(KeyId=kms_key_id, KeySpec="AES_256")
    return {
        "plaintext_key": resp["Plaintext"],
        "encrypted_key": resp["CiphertextBlob"],
        "key_id": resp["KeyId"],
    }


def encrypt_data(plaintext_bytes, kms_key_id, region="us-east-1"):
    """Encrypt data using envelope encryption with AWS KMS."""
    key_data = generate_data_key(kms_key_id, region)
    nonce = os.urandom(NONCE_SIZE)
    aesgcm = AESGCM(key_data["plaintext_key"])
    ciphertext = aesgcm.encrypt(nonce, plaintext_bytes, None)

    # Zero out plaintext key from memory
    key_data["plaintext_key"] = b"\x00" * 32

    envelope = {
        "encrypted_data_key": base64.b64encode(key_data["encrypted_key"]).decode(),
        "nonce": base64.b64encode(nonce).decode(),
        "ciphertext": base64.b64encode(ciphertext).decode(),
        "kms_key_id": key_data["key_id"],
        "algorithm": "AES-256-GCM",
        "envelope_version": 1,
    }
    return envelope


def decrypt_data(envelope, region="us-east-1"):
    """Decrypt envelope-encrypted data using AWS KMS."""
    kms = boto3.client("kms", region_name=region)
    encrypted_key = base64.b64decode(envelope["encrypted_data_key"])
    resp = kms.decrypt(CiphertextBlob=encrypted_key)
    plaintext_key = resp["Plaintext"]

    nonce = base64.b64decode(envelope["nonce"])
    ciphertext = base64.b64decode(envelope["ciphertext"])
    aesgcm = AESGCM(plaintext_key)
    plaintext = aesgcm.decrypt(nonce, ciphertext, None)

    # Zero out plaintext key
    plaintext_key = b"\x00" * 32
    return plaintext


def encrypt_file(input_path, output_path, kms_key_id, region="us-east-1"):
    """Encrypt a file using envelope encryption."""
    with open(input_path, "rb") as f:
        plaintext = f.read()
    envelope = encrypt_data(plaintext, kms_key_id, region)
    with open(output_path, "w") as f:
        json.dump(envelope, f, indent=2)
    return {
        "input": str(input_path),
        "output": str(output_path),
        "original_size": len(plaintext),
        "kms_key_id": envelope["kms_key_id"],
    }


def decrypt_file(input_path, output_path, region="us-east-1"):
    """Decrypt an envelope-encrypted file."""
    with open(input_path, "r") as f:
        envelope = json.load(f)
    plaintext = decrypt_data(envelope, region)
    with open(output_path, "wb") as f:
        f.write(plaintext)
    return {"input": str(input_path), "output": str(output_path), "decrypted_size": len(plaintext)}


def list_kms_keys(region="us-east-1"):
    """List available KMS keys."""
    kms = boto3.client("kms", region_name=region)
    paginator = kms.get_paginator("list_keys")
    keys = []
    for page in paginator.paginate():
        for key in page["Keys"]:
            try:
                desc = kms.describe_key(KeyId=key["KeyId"])
                meta = desc["KeyMetadata"]
                keys.append({
                    "key_id": meta["KeyId"],
                    "arn": meta["Arn"],
                    "description": meta.get("Description", ""),
                    "state": meta["KeyState"],
                    "key_usage": meta["KeyUsage"],
                    "origin": meta["Origin"],
                })
            except ClientError:
                keys.append({"key_id": key["KeyId"], "error": "access denied"})
    return {"keys": keys, "total": len(keys)}


def audit_key_policy(key_id, region="us-east-1"):
    """Audit a KMS key's policy for overly permissive access."""
    kms = boto3.client("kms", region_name=region)
    policy = json.loads(kms.get_key_policy(KeyId=key_id, PolicyName="default")["Policy"])
    findings = []
    for stmt in policy.get("Statement", []):
        principal = stmt.get("Principal", {})
        if principal == "*" or principal.get("AWS") == "*":
            findings.append({
                "severity": "HIGH",
                "finding": "Key policy allows access to all AWS principals",
                "statement_id": stmt.get("Sid", "unknown"),
            })
    return {"key_id": key_id, "policy": policy, "findings": findings}


def main():
    if not boto3 or not AESGCM:
        print(json.dumps({"error": "boto3 and cryptography required"}))
        return
    parser = argparse.ArgumentParser(description="AWS KMS Envelope Encryption Agent")
    parser.add_argument("--region", default="us-east-1")
    sub = parser.add_subparsers(dest="command")
    e = sub.add_parser("encrypt", help="Encrypt file with envelope encryption")
    e.add_argument("--input", required=True)
    e.add_argument("--output", required=True)
    e.add_argument("--key-id", required=True, help="KMS key ID or ARN")
    d = sub.add_parser("decrypt", help="Decrypt envelope-encrypted file")
    d.add_argument("--input", required=True)
    d.add_argument("--output", required=True)
    sub.add_parser("list-keys", help="List KMS keys")
    a = sub.add_parser("audit", help="Audit KMS key policy")
    a.add_argument("--key-id", required=True)
    args = parser.parse_args()
    if args.command == "encrypt":
        result = encrypt_file(args.input, args.output, args.key_id, args.region)
    elif args.command == "decrypt":
        result = decrypt_file(args.input, args.output, args.region)
    elif args.command == "list-keys":
        result = list_kms_keys(args.region)
    elif args.command == "audit":
        result = audit_key_policy(args.key_id, args.region)
    else:
        parser.print_help()
        return
    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
process.py10.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Envelope Encryption with AWS KMS

Implements envelope encryption pattern using AWS KMS for master key management
and local AES-256-GCM for data encryption.

Requirements:
    pip install boto3 cryptography

Usage:
    python process.py encrypt --key-id alias/my-key --input data.json --output data.json.enc
    python process.py decrypt --input data.json.enc --output data.json
    python process.py encrypt-file --key-id alias/my-key --input largefile.zip --output largefile.zip.enc
    python process.py re-encrypt --key-id alias/new-key --input data.json.enc --output data.json.reenc

Environment:
    AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION
    or ~/.aws/credentials
"""

import os
import sys
import json
import struct
import argparse
import logging
import base64
import ctypes
from pathlib import Path
from typing import Dict, Optional, Tuple

import boto3
from botocore.exceptions import ClientError
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

NONCE_LENGTH = 12
MAGIC_BYTES = b"ENVKMS01"


def secure_wipe(data: bytearray):
    """Attempt to securely wipe sensitive data from memory."""
    if isinstance(data, (bytearray, memoryview)):
        for i in range(len(data)):
            data[i] = 0


def generate_data_key(
    kms_client,
    key_id: str,
    encryption_context: Optional[Dict[str, str]] = None,
) -> Tuple[bytes, bytes]:
    """
    Generate a data encryption key (DEK) using AWS KMS.

    Returns:
        Tuple of (plaintext_key, encrypted_key)
    """
    params = {
        "KeyId": key_id,
        "KeySpec": "AES_256",
    }
    if encryption_context:
        params["EncryptionContext"] = encryption_context

    try:
        response = kms_client.generate_data_key(**params)
        plaintext_key = response["Plaintext"]
        encrypted_key = response["CiphertextBlob"]
        logger.info(f"Generated data key using KMS key: {key_id}")
        return plaintext_key, encrypted_key
    except ClientError as e:
        logger.error(f"KMS GenerateDataKey failed: {e}")
        raise


def decrypt_data_key(
    kms_client,
    encrypted_key: bytes,
    encryption_context: Optional[Dict[str, str]] = None,
) -> bytes:
    """Decrypt an encrypted data key using AWS KMS."""
    params = {"CiphertextBlob": encrypted_key}
    if encryption_context:
        params["EncryptionContext"] = encryption_context

    try:
        response = kms_client.decrypt(**params)
        return response["Plaintext"]
    except ClientError as e:
        logger.error(f"KMS Decrypt failed: {e}")
        raise


def re_encrypt_data_key(
    kms_client,
    encrypted_key: bytes,
    new_key_id: str,
    source_context: Optional[Dict[str, str]] = None,
    dest_context: Optional[Dict[str, str]] = None,
) -> bytes:
    """Re-encrypt a data key with a new master key without exposing plaintext."""
    params = {
        "CiphertextBlob": encrypted_key,
        "DestinationKeyId": new_key_id,
    }
    if source_context:
        params["SourceEncryptionContext"] = source_context
    if dest_context:
        params["DestinationEncryptionContext"] = dest_context

    try:
        response = kms_client.re_encrypt(**params)
        return response["CiphertextBlob"]
    except ClientError as e:
        logger.error(f"KMS ReEncrypt failed: {e}")
        raise


def envelope_encrypt(
    data: bytes,
    kms_client,
    key_id: str,
    encryption_context: Optional[Dict[str, str]] = None,
) -> bytes:
    """
    Encrypt data using envelope encryption.

    Output format:
        MAGIC (8 bytes) || encrypted_key_len (4 bytes, big-endian) ||
        encrypted_key (variable) || context_len (4 bytes) || context_json (variable) ||
        nonce (12 bytes) || ciphertext+tag (variable)
    """
    plaintext_key, encrypted_key = generate_data_key(kms_client, key_id, encryption_context)

    try:
        nonce = os.urandom(NONCE_LENGTH)
        aesgcm = AESGCM(plaintext_key)
        ciphertext = aesgcm.encrypt(nonce, data, associated_data=None)
    finally:
        # Wipe plaintext key
        if isinstance(plaintext_key, bytes):
            plaintext_key = bytearray(plaintext_key)
        secure_wipe(plaintext_key)

    context_json = json.dumps(encryption_context or {}).encode()

    output = bytearray()
    output.extend(MAGIC_BYTES)
    output.extend(struct.pack(">I", len(encrypted_key)))
    output.extend(encrypted_key)
    output.extend(struct.pack(">I", len(context_json)))
    output.extend(context_json)
    output.extend(nonce)
    output.extend(ciphertext)

    return bytes(output)


def envelope_decrypt(
    data: bytes,
    kms_client,
) -> Tuple[bytes, Dict]:
    """
    Decrypt envelope-encrypted data.

    Returns:
        Tuple of (plaintext, encryption_context)
    """
    if not data.startswith(MAGIC_BYTES):
        raise ValueError("Invalid envelope encryption format")

    offset = len(MAGIC_BYTES)

    enc_key_len = struct.unpack(">I", data[offset : offset + 4])[0]
    offset += 4
    encrypted_key = data[offset : offset + enc_key_len]
    offset += enc_key_len

    ctx_len = struct.unpack(">I", data[offset : offset + 4])[0]
    offset += 4
    context_json = data[offset : offset + ctx_len]
    offset += ctx_len
    encryption_context = json.loads(context_json.decode())

    nonce = data[offset : offset + NONCE_LENGTH]
    offset += NONCE_LENGTH
    ciphertext = data[offset:]

    plaintext_key = decrypt_data_key(
        kms_client,
        encrypted_key,
        encryption_context if encryption_context else None,
    )

    try:
        aesgcm = AESGCM(plaintext_key)
        plaintext = aesgcm.decrypt(nonce, ciphertext, associated_data=None)
    finally:
        if isinstance(plaintext_key, bytes):
            plaintext_key = bytearray(plaintext_key)
        secure_wipe(plaintext_key)

    return plaintext, encryption_context


def envelope_re_encrypt(
    data: bytes,
    kms_client,
    new_key_id: str,
) -> bytes:
    """Re-encrypt an envelope-encrypted file with a new KMS key."""
    if not data.startswith(MAGIC_BYTES):
        raise ValueError("Invalid envelope encryption format")

    offset = len(MAGIC_BYTES)
    enc_key_len = struct.unpack(">I", data[offset : offset + 4])[0]
    offset += 4
    encrypted_key = data[offset : offset + enc_key_len]
    offset += enc_key_len

    ctx_len = struct.unpack(">I", data[offset : offset + 4])[0]
    ctx_start = offset + 4
    context_json = data[ctx_start : ctx_start + ctx_len]
    encryption_context = json.loads(context_json.decode())

    remainder = data[ctx_start + ctx_len :]

    new_encrypted_key = re_encrypt_data_key(
        kms_client,
        encrypted_key,
        new_key_id,
        source_context=encryption_context if encryption_context else None,
        dest_context=encryption_context if encryption_context else None,
    )

    output = bytearray()
    output.extend(MAGIC_BYTES)
    output.extend(struct.pack(">I", len(new_encrypted_key)))
    output.extend(new_encrypted_key)
    output.extend(struct.pack(">I", ctx_len))
    output.extend(context_json)
    output.extend(remainder)

    logger.info(f"Re-encrypted data key with new KMS key: {new_key_id}")
    return bytes(output)


def encrypt_file(
    input_path: str,
    output_path: str,
    kms_client,
    key_id: str,
    encryption_context: Optional[Dict[str, str]] = None,
) -> Dict:
    """Encrypt a file using envelope encryption."""
    plaintext = Path(input_path).read_bytes()

    if encryption_context is None:
        encryption_context = {"filename": Path(input_path).name}

    encrypted = envelope_encrypt(plaintext, kms_client, key_id, encryption_context)

    Path(output_path).write_bytes(encrypted)
    logger.info(f"Encrypted {input_path} -> {output_path}")

    return {
        "input": input_path,
        "output": output_path,
        "original_size": len(plaintext),
        "encrypted_size": len(encrypted),
        "kms_key_id": key_id,
        "encryption_context": encryption_context,
    }


def decrypt_file(input_path: str, output_path: str, kms_client) -> Dict:
    """Decrypt an envelope-encrypted file."""
    data = Path(input_path).read_bytes()
    plaintext, context = envelope_decrypt(data, kms_client)

    Path(output_path).write_bytes(plaintext)
    logger.info(f"Decrypted {input_path} -> {output_path}")

    return {
        "input": input_path,
        "output": output_path,
        "decrypted_size": len(plaintext),
        "encryption_context": context,
    }


def main():
    parser = argparse.ArgumentParser(description="Envelope Encryption with AWS KMS")
    parser.add_argument("--region", default=None, help="AWS region")
    parser.add_argument("--profile", default=None, help="AWS profile")
    subparsers = parser.add_subparsers(dest="command")

    enc = subparsers.add_parser("encrypt", help="Encrypt a file")
    enc.add_argument("--key-id", required=True, help="KMS key ID or alias")
    enc.add_argument("--input", "-i", required=True, help="Input file")
    enc.add_argument("--output", "-o", required=True, help="Output file")
    enc.add_argument("--context", help="Encryption context as JSON string")

    dec = subparsers.add_parser("decrypt", help="Decrypt a file")
    dec.add_argument("--input", "-i", required=True, help="Encrypted input file")
    dec.add_argument("--output", "-o", required=True, help="Output file")

    reenc = subparsers.add_parser("re-encrypt", help="Re-encrypt with new key")
    reenc.add_argument("--key-id", required=True, help="New KMS key ID or alias")
    reenc.add_argument("--input", "-i", required=True, help="Encrypted input file")
    reenc.add_argument("--output", "-o", required=True, help="Output file")

    args = parser.parse_args()

    session_kwargs = {}
    if args.region:
        session_kwargs["region_name"] = args.region
    if args.profile:
        session_kwargs["profile_name"] = args.profile

    session = boto3.Session(**session_kwargs)
    kms_client = session.client("kms")

    if args.command == "encrypt":
        context = json.loads(args.context) if args.context else None
        result = encrypt_file(args.input, args.output, kms_client, args.key_id, context)
        print(json.dumps(result, indent=2))
    elif args.command == "decrypt":
        result = decrypt_file(args.input, args.output, kms_client)
        print(json.dumps(result, indent=2))
    elif args.command == "re-encrypt":
        data = Path(args.input).read_bytes()
        result = envelope_re_encrypt(data, kms_client, args.key_id)
        Path(args.output).write_bytes(result)
        print(json.dumps({"input": args.input, "output": args.output, "new_key_id": args.key_id}))
    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 2.2 KB
Keep exploring