Amazon Key Management Service (KMS) is a fully managed encryption service provided by AWS that enables users to encrypt and decrypt their data efficiently and at scale. KMS, as the name suggests, lets you create, store and manage cryptographic keys. These are keys that users can use to convert plaintext to ciphertext and vice versa. KMS is integrated with all the other AWS services, such as EC2, RDS, S3, SSM, and many others. KMS supports various encryption keys, such as AWS Managed Keys, AWS Managed Customer Keys, and Customer Master Keys (CMK). This Boto3 KMS tutorial covers managing KMS keys, KMS Policies, Key Aliases, and Key Grants using the Python Boto3 library.

Prerequisites

You must configure your Python environment to start managing Amazon KMS Keys programmatically through the AWS APIs using the Boto3 library. We also suggest you use aws-vault for managing access to multiple AWS environments.

In general, here’s what you need to have installed:

  • Python 3
  • Boto3
  • AWS CLI tools

Alternatively, you can use a Cloud9 IDE.

Connect to Amazon KMS using Boto3

The KMS Boto3 library provides a low-level API client to manage AWS KMS APIs.

  • The client allows you to access the low-level API data. For example, you can access API response data in JSON format.

Here’s how you can instantiate the Boto3 KMS client to start working with Amazon KMS APIs:

import boto3
AWS_REGION = "us-east-2"
kms_client = boto3.client("kms", region_name=AWS_REGION)

Working with KMS keys using Boto3

Amazon KMS is used to encrypt data in AWS. The primary purpose of the AWS KMS is to store and manage encryption keys. Data encryption is essential if you have sensitive data that unauthorized users must not access.

KMS supports two methods to implement encryption at rest, Client-Side Encryption and Server Side Encryption.

  • Client-Side Encryption lets you encrypt the data at the client-side and send it to the AWS services like S3, EBS, Redshift, etc.
  • Server-Side Encryption AWS encrypts the data and manages the keys for you.

Creating KMS Key

To create a unique Customer Master key (CMK) key, you need to use the create_key() method from the Boto3 library.

You can use the create_key() method to create symmetric or asymmetric KMS keys.

  • Symmetric KMS keys:
    • Symmetric KMS keys Contain a 256-bit single encryption key used for both encrypt and decrypt operations. 
    • Symmetric KMS keys never leave AWS KMS unencrypted.
  • Asymmetric KMS keys:
    • Asymmetric KMS keys can contain an RSA or an Elliptic Curve (ECC) key pair.
    • The private key in the Asymmetric Key pair never leaves AWS KMS unencrypted. However, You can use the public key within AWS KMS by calling the AWS KMS API operations or downloading the public key to operate outside KMS.
    • You can use KMS keys with RSA key pairs to encrypt or decrypt data or sign and verify messages (but not both).
    • You can only use KMS keys with ECC key pairs to sign and verify messages.
import json
import logging
from datetime import date, datetime
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def json_datetime_serializer(obj):
    """
    Helper method to serialize datetime fields
    """
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

def create_kms_key():
    """
    Creates a unique customer managed KMS key.
    """
    try:
        response = kms_client.create_key(Description='hands-on-cloud-cmk',
                                         Tags=[{
                                             'TagKey': 'Name',
                                             'TagValue': 'hands-on-cloud-cmk'
                                         }])
    except ClientError:
        logger.exception('Could not create a CMK key.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    logger.info('Creating a symetric CMK...')
    kms = create_kms_key()
    logger.info(
        f'Symetric CMK is created with details: {json.dumps(kms, indent=4, default=json_datetime_serializer)}'
    )

The optional arguments used in the above example are:

  • DescriptionSpecifies a description of the KMS key.
  • TagsAssigns one or more AWS resource tags to the KMS key.

In the above example, we are creating a symmetric encryption key. To create Asymmetric encryption keys, we need to specify the KeySpec argument as part of the create_key() method. To get more details, refer here.

Also, we’re using additional json_datetime_serializer() method to serialize (convert to string) datetime.datetime fields returned by the create_key() method.

The create_key() method returns a python dictionary object as a response.

Here is the code execution output:

Boto3 KMS - Create KMS Key
Create KMS Key

Enabling KMS Key

To enable a KMS key, you need to use the enable_key() method from the Boto3 library.

This method changes the state of the KMS key from disabled to enabled, allowing you to use that key in encryption operations.

import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def enable_kms_key(key_id):
    """
    Sets the key state of a KMS key to enabled..
    """
    try:
        response = kms_client.enable_key(KeyId=key_id)
    except ClientError:
        logger.exception('Could not enable a KMS key.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    logger.info('Enabling a KMS key...')
    kms = enable_kms_key(KEY_ID)
    logger.info(f'KMS key ID {KEY_ID} enabled for use.')

The required argument is:

  • KeyIdSpecifies key ID or key ARN of the KMS key to change state to enabled.

The enable_key() method does not return any output response upon successful execution.

Here is the code execution output:

Enable KMS Key
Enable KMS Key

Disabling KMS Key

To disable a KMS key, you need to use the disable_key() method from the Boto3 library.

As the name suggests, this method changes the state of the KMS key from enabled to disabled, stopping you from using that key in encryption operations.

import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def disable_kms_key(key_id):
    """
    Sets the key state of a KMS key to disabled..
    """
    try:
        response = kms_client.disable_key(KeyId=key_id)
    except ClientError:
        logger.exception('Could not disable a KMS key.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    logger.info('Disabling a KMS key...')
    kms = disable_kms_key(KEY_ID)
    logger.info(f'KMS key ID {KEY_ID} disabled for use.')

The required argument is:

  • KeyIdSpecifies key ID or key ARN of the KMS key to change state to enabled.

The disable_key() method does not return any output response upon successful execution.

Here is the code execution output:

Disable KMS Key
Disable KMS Key

Describing KMS Key

To describe a KMS key, you need to use the describe_key() method from the Boto3 library.

As the name suggests, this method returns detailed information about the specified key ID, including the key ARN, the key state, creation date (and deletion date, if applicable), and the origin date and expiration date (if any) of the underlying key material.

import json
import logging
from datetime import date, datetime
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def json_datetime_serializer(obj):
    """
    Helper method to serialize datetime fields
    """
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

def describe_kms_key(key_id):
    """
    Provides detailed information about a KMS key.
    """
    try:
        response = kms_client.describe_key(KeyId=key_id)
    except ClientError:
        logger.exception('Could not describe a KMS key.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    logger.info('Getting information about KMS key...')
    kms = describe_kms_key(KEY_ID)
    logger.info(
        f'Key Details: {json.dumps(kms, indent=4, default=json_datetime_serializer)}'
    )

The required argument is:

  • KeyIdSpecify key ID, key ARN, alias name, or alias ARN to get detailed information about the specified key.

Also, we’re using additional json_datetime_serializer() method to serialize (convert to string) datetime.datetime fields returned by the describe_key() method.

The describe_key() method returns a python dictionary object as a response.

Here is the code execution output:

Describe KMS Key
Describe KMS Key

Listing KMS Keys

To get a list of all KMS keys from a given region, you need to use the list_keys() method from the Boto3 library.

As the name suggests, this method returns a list of all KMS keys, including the Key ID and ARN, from your account in the specified region.

We will use the Boto3 library paginator object to get the complete output from the list_keys() method.

Some AWS requests return incomplete output, therefore, require subsequent requests to get the complete result. The process of sending subsequent requests to continue where a previous request left off is called pagination.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def list_kms_keys(max_items):
    """
    Gets a list of all KMS keys.
    """
    try:
        # creating paginator object for list_keys() method
        paginator = kms_client.get_paginator('list_keys')
        # creating a PageIterator from the paginator
        response_iterator = paginator.paginate(
            PaginationConfig={'MaxItems': max_items})
        full_result = response_iterator.build_full_result()
        key_list = []
        for page in full_result['Keys']:
            key_list.append(page)
    except ClientError:
        logger.exception('Could not list KMS Keys.')
        raise
    else:
        return key_list

if __name__ == '__main__':
    # Constants
    MAX_ITEMS = 10
    logger.info('Getting a list of KMS keys...')
    kms_keys = list_kms_keys(MAX_ITEMS)
    for kms_key in kms_keys:
        logger.info(f'Key Details: {kms_key}')

The list_keys() method returns a python dictionary object as a response containing the key ID and ARN of each KMS key.

Here is the code execution output:

List KMS Keys
List KMS Keys

Deleting KMS Key

To delete a KMS key, you need to use the schedule_key_deletion() method from the Boto3 library.

By default, KMS applies a waiting period of 30 days when a key is deleted, but you have the option to specify a waiting period of 7-30 days. When the deletion operation is executed successfully, the state of the KMS key changes to the PendingDeletion, and you can’t use the key in any cryptographic functions.

Also, we’re using additional json_datetime_serializer() method to serialize (convert to string) datetime.datetime fields returned by the schedule_key_deletion() method.

import json
import logging
from datetime import date, datetime
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def json_datetime_serializer(obj):
    """
    Helper method to serialize datetime fields
    """
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

def delete_kms_key(key_id, pending_window_in_days):
    """
    Schedules the deletion of a KMS key.
    """
    try:
        response = kms_client.schedule_key_deletion(
            KeyId=key_id, PendingWindowInDays=pending_window_in_days)
    except ClientError:
        logger.exception('Could not delete a KMS key.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    PENDING_WINDOW_IN_DAYS = 7
    logger.info('Scheduling deletion of KMS key...')
    kms = delete_kms_key(KEY_ID, PENDING_WINDOW_IN_DAYS)
    logger.info(
        f'Deletion Details: {json.dumps(kms, indent=4, default=json_datetime_serializer)}'
    )

The required argument is:

  • KeyIdSpecifies key ID or key ARN of the KMS key to be deleted.

The optional argument used in the above example is:

  • PendingWindowInDaysSpecifies the waiting period, specified in several days.

The schedule_key_deletion() method returns a python dictionary object as a response, including the deletion date of the key.

Here is the code execution output:

Delete KMS Key
Delete KMS Key

Cancel KMS key deletion

To cancel the KMS key deletion, you need to use the cancel_key_deletion() method from the Boto3 library.

Upon successful execution of the cancel_key_deletion() method, the key state of the KMS key is Disabled. To enable the KMS key, we need to use the EnableKey method.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def enable_kms_key(key_id):
    """
    Sets the key state of a KMS key to enabled..
    """
    try:
        response = kms_client.enable_key(KeyId=key_id)
    except ClientError:
        logger.exception('Could not enable a KMS key.')
        raise
    else:
        return response

def cancel_kms_key_deletion(key_id):
    """
    Cancels the deletion of a KMS key.
    """
    try:
        response = kms_client.cancel_key_deletion(KeyId=key_id)
        # After canclling the deletion, enable the key again
        _ = enable_kms_key(key_id)
    except ClientError:
        logger.exception('Could not cancel key deletion.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    logger.info('Canceling deletion of KMS key...')
    kms = cancel_kms_key_deletion(KEY_ID)
    logger.info(
        f'Key Deletion cancelled and enabled for encryption operations. \nDetails: {json.dumps(kms, indent=4)}'
    )

The required argument is:

  • KeyIdSpecifies key ID or key ARN of the KMS key whose deletion is being canceled.

The cancel_key_deletion() method returns a python dictionary object as a response, including the key ARN.

Here is the code execution output:

Cancel KMS Key Deletion
Cancel KMS Key Deletion

Working with KMS keys policies

Key policies are used to control access to KMS keys in AWS KMS. Each key policy document determines which users have permission to use the KMS key and how they can use it. You can also apply IAM policies and grants to control access to the KMS key.

Every KMS key must have precisely one key policy.

Applying KMS key policy

To apply a policy to the KMS key, you need to use the put_key_policy() method from the Boto3 library.

When a key is created, by default, a policy is set and gives the root user that owns the KMS key full access to the KMS key.

The put_key_policy() method takes a key ID and JSON formatted AWS KMS policy as input.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def put_policy_kms_key(key_id, policy):
    """
    Attaches a key policy to the specified KMS key.
    """
    try:
        response = kms_client.put_key_policy(KeyId=key_id,
                                             PolicyName='default',
                                             Policy=policy)
    except ClientError:
        logger.exception('Could not attach a key policy.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    POLICY = '''
    {
        "Version": "2012-10-17",
        "Statement": [{
            "Sid": "Allowing Access",
            "Effect": "Allow",
            "Principal": {"AWS": [
                "arn:aws:iam::979450158315:user/iamadmin"
            ]},
            "Action": "kms:*",
            "Resource": "*"
        }]
    }'''
    logger.info('Attaching a key policy...')
    kms = put_policy_kms_key(KEY_ID, POLICY)
    logger.info('Key policy is attached.')

The required arguments are:

  • KeyIdSpecifies the key policy on the specified KMS key. Specify the key ID or key ARN of the KMS key.
  • PolicyName:  Specifies the name of the key policy. The only valid value is the default.
  • PolicySpecifies the key policy to attach to the KMS key.

In the above example, we are attaching a policy that allows all access to the IAM user.

The put_key_policy() method does not return any output on successful operation.

Here is the code execution output:

Put KMS Key policy
Put KMS Key policy

Getting KMS key policy

To get a key policy attached to a specific KMS key, you need to use the get_key_policy() method from the Boto3 library.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def get_policy_kms_key(key_id):
    """
    Gets a key policy attached to the specified KMS key.
    """
    try:
        response = kms_client.get_key_policy(KeyId=key_id,
                                             PolicyName='default')
    except ClientError:
        logger.exception('Could not get the key policy.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    logger.info('Gettign a key policy...')
    kms = get_policy_kms_key(KEY_ID)
    logger.info(f'Key policy: {json.dumps(kms, indent=4)}')

The required arguments are:

  • KeyIdSpecifies the key ID or key ARN of the KMS key.
  • PolicyName:  Specifies the name of the key policy. The only valid value is the default.

In the above example, we are getting a policy attached in the last example.

The get_key_policy() method returns a python dictionary object as a response, including the attached key policy.

Here is the code execution output:

Get KMS Key policy
Get KMS Key policy

Listing KMS key policies

To the names of the key policies attached to a KMS key, you need to use the list_key_policies() method from the Boto3 library.

The output from this method is used to get policy names that we can pass in a GetKeyPolicy operation. However, the only valid policy name is the default.

We will use the Boto3 library paginator object to get the complete output from the list_key_policies() method.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def list_kms_policies(key_id, max_items):
    """
    Gets the names of the key policies that are attached to a KMS key.
    """
    try:
        # creating paginator object for list_key_policies() method
        paginator = kms_client.get_paginator('list_key_policies')
        # creating a PageIterator from the paginator
        response_iterator = paginator.paginate(
            KeyId=key_id, PaginationConfig={'MaxItems': max_items})
        full_result = response_iterator.build_full_result()
        policy_list = []
        for page in full_result['PolicyNames']:
            policy_list.append(page)
    except ClientError:
        logger.exception('Could not list KMS Key policies.')
        raise
    else:
        return policy_list

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    MAX_ITEMS = 10
    logger.info('Getting a list of KMS key policies...')
    kms_policies = list_kms_policies(KEY_ID, MAX_ITEMS)
    for kms_policy in kms_policies:
        logger.info(f'Key Policy: {kms_policy}')

The required argument is:

  • KeyIdSpecifies the key ID or key ARN of the KMS key.

The list_key_policies() method returns a python dictionary object as a response containing key policy names.

Here is the code execution output:

List KMS Key policies
List KMS Key policies

Working with KMS keys grants

A key grant allows AWS IAM principals to use AWS KMS keys in cryptographic operations. Grants are often used to provide temporary permissions because you can create a grant, use its permissions, and delete it without changing your IAM or key policies.

KMS Key PoliciesKMS Key Grants
A KMS key can have only one key policy.A KMS key can have multiple grants.
You can use key policies to allow or deny access to other IAM principles.You can use grants to allow access to other AWS principles but not deny them.
The key policy is accessible in the console and in the programmatic APIs/CLIs.Key Grants are only programmatically accessible.
The KMS key policy name is set to default only.Key Grants can be given a custom name, like “hands-on-cloud-grant.”
AWS KMS Key Policies vs. Grants

Creating grant to KMS key

To create a Key grant for a specific key, you need to use the create_grant() method from the Boto3 library.

While executing the create_grant() operation of the KMS key, that key must be in a compatible state.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def create_kms_key_grant(principal, key_id, operations):
    """
    Adds a grant to a KMS key.
    """
    try:
        response = kms_client.create_grant(GranteePrincipal=principal,
                                           KeyId=key_id,
                                           Operations=operations)
    except ClientError:
        logger.exception('Could not create a key grant.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    PRINCIPAL = 'arn:aws:iam::979450158315:role/hands-on-cloud-kms-role'
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    OPERATIONS = ['Encrypt', 'Decrypt']
    logger.info('Creating a key grant...')
    kms = create_kms_key_grant(PRINCIPAL, KEY_ID, OPERATIONS)
    logger.info(
        f'Key grant is created with details: {json.dumps(kms, indent=4)}')

The required arguments are:

  • KeyIdSpecifies the key ID or key ARN of the KMS key.
  • GranteePrincipal: Specifies the IAM identity that gets the permissions specified in the grant.
  • OperationsSpecifies a list of operations that the grant permits.

In the above example, we create a grant that allows the hands-on-cloud-kms IAM role encrypting and decrypting data with the specified customer master key.

The create_grant() method returns a python dictionary object as a response, including the key grant token and ID.

Here is the code execution output:

Create KMS Key grant
Create a KMS Key grant

Listing KMS key grants

To list the key grants for a KMS key, you need to use the list_grants() method from the Boto3 library.

We will use the Boto3 library paginator object to get the complete output from the list_grants() method.

Also, we’re using additional json_datetime_serializer() method to serialize (convert to string) datetime.datetime fields returned by the list_grants() method.

import json
import logging
from datetime import date, datetime
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def json_datetime_serializer(obj):
    """
    Helper method to serialize datetime fields
    """
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

def list_kms_grants(key_id, max_items):
    """
    Gets a list of all grants for the specified KMS key.
    """
    try:
        # creating paginator object for list_grants() method
        paginator = kms_client.get_paginator('list_grants')
        # creating a PageIterator from the paginator
        response_iterator = paginator.paginate(
            KeyId=key_id, PaginationConfig={'MaxItems': max_items})
        full_result = response_iterator.build_full_result()
        grants_list = []
        for page in full_result['Grants']:
            grants_list.append(page)
    except ClientError:
        logger.exception('Could not list KMS Key grants.')
        raise
    else:
        return grants_list

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    MAX_ITEMS = 10
    logger.info('Getting a list of KMS key grants...')
    key_grants = list_kms_grants(KEY_ID, MAX_ITEMS)
    for grant in key_grants:
        logger.info(
            f'Key Grant: {json.dumps(grant, indent=4, default=json_datetime_serializer)}'
        )

The required argument is:

  • KeyIdSpecifies the key ID or key ARN of the KMS key.

The list_grants() method returns a python dictionary object as a response containing key grants details.

Here is the code execution output:

List KMS Key grants
List KMS Key grants

Revoking KMS key grants

To revoke a key grant from a KMS key, you need to use the revoke_grant() method from the Boto3 library.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def revoke_kms_key_grant(key_id, grant_id):
    """
    Deletes the specified grant from a KMS key.
    """
    try:
        response = kms_client.revoke_grant(KeyId=key_id, GrantId=grant_id)
    except ClientError:
        logger.exception('Could not revoke a key grant.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    GRANT_ID = 'a3ef5fc2f363d40f42b609bc259972be0a73340b766aabace579cee6360475b4'
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    logger.info('Revoking a key grant...')
    kms = revoke_kms_key_grant(KEY_ID, GRANT_ID)
    logger.info(f'Key grant is revoked from key: {KEY_ID}')

The required arguments are:

  • KeyId: Specifies the key ID or key ARN of the KMS key.
  • GrantId: Specifies the grant to revoke.

The revoke_grant() method does not return any output response upon successful execution.

Here is the code execution output:

Revoke KMS Key grant
Revoke KMS Key grant

Working with KMS keys aliases

A key alias is an optional name for a customer master key. The alias name must be unique in the AWS region and account. Each CMK can have multiple aliases, but each alias points to only one CMK.

Creating a KMS key alias

To create Key alias for a specific key, you need to use the create_alias() method from the Boto3 library.

Key alias must start with the prefix alias/. The alias name cannot begin with alias/aws/. The alias/aws/ prefix is reserved for Amazon Web Services managed keys .

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def create_kms_key_alias(key_id, alias_name):
    """
    Creates a custom name/alias for a KMS key.
    """
    try:
        response = kms_client.create_alias(AliasName=alias_name,
                                           TargetKeyId=key_id)
    except ClientError:
        logger.exception('Could not create a key alias.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    ALIAS_NAME = 'alias/hands-on-cloud-kms-alias'
    logger.info('Creating a key alias...')
    kms = create_kms_key_alias(KEY_ID, ALIAS_NAME)
    logger.info('Key alias is created.')

The required arguments are:

  • AliasNameSpecifies the alias name. Must be a string of 1-256 characters, and can contain only alphanumeric characters, forward slashes (/), underscores (_), and dashes (-).
  • TargetKeyIdSpecifies the key ID or key ARN of the KMS key.

The create_alias() method does not return any output response upon successful execution.

Here is the code execution output:

Create KMS Key alias
Create KMS Key alias

Listing KMS key aliases

To get the list of KMS key aliases for a specified key, you need to use the list_aliases() method from the Boto3 library.

We will use the Boto3 library paginator object to get the complete output from the list_aliases() method.

Also, we’re using additional json_datetime_serializer() method to serialize (convert to string) datetime.datetime fields returned by the list_aliases() method.

import json
import logging
from datetime import date, datetime
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def json_datetime_serializer(obj):
    """
    Helper method to serialize datetime fields
    """
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

def list_kms_aliases(key_id, max_items):
    """
    Gets a list of aliases of a KMS key.
    """
    try:
        # creating paginator object for list_aliases() method
        paginator = kms_client.get_paginator('list_aliases')
        # creating a PageIterator from the paginator
        response_iterator = paginator.paginate(
            KeyId=key_id, PaginationConfig={'MaxItems': max_items})
        full_result = response_iterator.build_full_result()
        aliases_list = []
        for page in full_result['Aliases']:
            aliases_list.append(page)
    except ClientError:
        logger.exception('Could not list KMS aliases.')
        raise
    else:
        return aliases_list

if __name__ == '__main__':
    # Constants
    KEY_ID = '1e7ca6bf-884d-4e46-8195-f9aa5a3c1569'
    MAX_ITEMS = 10
    logger.info('Getting KMS key aliases...')
    kms_aliases = list_kms_aliases(KEY_ID, MAX_ITEMS)
    for kms_alias in kms_aliases:
        logger.info(
            f'Key Alias Details: {json.dumps(kms_alias, indent=4, default=json_datetime_serializer)}'
        )

The optional argument used in the above example is:

  • KeyIdSpecifies the key ID or key ARN of the KMS key.

The list_aliases() method returns a python dictionary object as a response containing key aliases details.

Here is the code execution output:

List KMS Key aliases
List KMS Key aliases

Updating KMS key aliases

To associate an existing KMS alias with a different KMS key, you need to use the update_alias() method from the Boto3 library.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def update_kms_key_alias(key_id, alias_name):
    """
    Associates an existing KMS alias with a different KMS key.
    """
    try:
        response = kms_client.update_alias(AliasName=alias_name,
                                           TargetKeyId=key_id)
    except ClientError:
        logger.exception('Could not update the key alias.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    TARGET_KEY_ID = '7b72033f-ee96-4803-9c7a-c54d6f02a32a'
    ALIAS_NAME = 'alias/hands-on-cloud-kms-alias'
    logger.info('Updating a key alias...')
    kms = update_kms_key_alias(TARGET_KEY_ID, ALIAS_NAME)
    logger.info('Key alias is Updated.')

The required arguments are:

  • AliasName: Specifies the alias that is changing its KMS key.
  • TargetKeyId:Specifies the key ID of the KMS key to associate with the alias.

The update_alias() method does not return any output response upon successful execution.

Here is the code execution output:

Update KMS Key alias
Update KMS Key alias

Getting the KMS key by the alias

To get a KMS key by its alias, you need to use the describe_key() method from the Boto3 library.

We have used this method previously; this example will use the key alias instead of the key ID. Also, we’re using additional json_datetime_serializer() method to serialize (convert to string) datetime.datetime fields returned by the list_aliases() method.

import json
import logging
from datetime import date, datetime
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def json_datetime_serializer(obj):
    """
    Helper method to serialize datetime fields
    """
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

def get_kms_key_by_alias(key_id):
    """
    Provides detailed information about a KMS key.
    """
    try:
        response = kms_client.describe_key(KeyId=key_id)
    except ClientError:
        logger.exception('Could not describe a KMS key.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ALIAS = 'alias/hands-on-cloud-kms-alias'
    logger.info('Getting information about KMS key...')
    kms = get_kms_key_by_alias(KEY_ALIAS)
    logger.info(
        f'Key Details: {json.dumps(kms, indent=4, default=json_datetime_serializer)}'
    )

The required argument is:

  • KeyIdSpecify key ID, key ARN, alias name, or alias ARN to get detailed information about the specified key.

The describe_key() method returns a python dictionary object as a response.

Here is the code execution output:

Get KMS Key by Alias
Get KMS Key by Alias

Deleting the KMS key alias

To delete a KMS key alias, you need to use the delete_alias() method from the Boto3 library.

import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def delete_kms_key_alias(key_alias):
    """
    Deletes the specified key alias.
    """
    try:
        response = kms_client.delete_alias(AliasName=key_alias)
    except ClientError:
        logger.exception('Could not delete a KMS key alias.')
        raise
    else:
        return response

if __name__ == '__main__':
    # Constants
    KEY_ALIAS = 'alias/hands-on-cloud-kms-alias'
    logger.info('Deleting KMS key alias...')
    kms = delete_kms_key_alias(KEY_ALIAS)
    logger.info('Key alias deleted.')

The required argument is:

  • AliasNameSpecifies key alias to be deleted.

The delete_alias() method does not return any output response upon successful execution.

Here is the code execution output:

Delete KMS Key alias
Delete KMS Key alias

Examples of using KMS

This section covers some of the real-life examples of working with KMS using the Boto3 library.

How to encrypt a string using KMS and Boto3 in Python?

To encrypt the string/secret using a KMS key, you need to use the encrypt() method from the Boto3 library.

In the below example, we will encrypt the string hands-on-cloud using a KMS key alias created during previous examples.

We will use the SYMMETRIC_DEFAULT encryption algorithm, the default algorithm for encryption.

import base64
import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def encrypt(secret, alias):
    """
    Encrypts plaintext into ciphertext by using a KMS key.
    """
    try:
        cipher_text = kms_client.encrypt(
            KeyId=alias,
            Plaintext=bytes(secret, encoding='utf8'),
        )
    except ClientError:
        logger.exception('Could not encrypt the string.')
        raise
    else:
        return base64.b64encode(cipher_text["CiphertextBlob"])

if __name__ == '__main__':
    # Constants
    SECRET = 'hands-on-cloud'
    KEY_ALIAS = 'alias/hands-on-cloud-kms-alias'
    logger.info('Encrypting...')
    kms = encrypt(SECRET, KEY_ALIAS)
    logger.info(f'Encrypted string: {kms}.')

The required arguments are:

  • KeyIdSpecifies the KMS key to use in the encryption.
  • Plaintext: Data string to be encrypted.

The encrypt() method returns CiphertextBlob (bytes) of the encrypted plaintext.

Here is the code execution output:

Encrypt a string using KMS
Encrypt a string using KMS

How to decrypt a string using KMS and Boto3 in Python?

To decrypt the Ciphertext using a KMS key, you need to use the decrypt() method from the Boto3 library.

In the below example, we will decrypt the ciphertext generated in the last example using a KMS key alias created during previous examples.

We will be using the SYMMETRIC_DEFAULT decryption algorithm, which is the default algorithm for decryption.

import base64
import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def decrypt(cipher_text, alias):
    """
    Decrypts ciphertext that was encrypted by a KMS key.
    """
    try:
        plain_text = kms_client.decrypt(KeyId=alias,
                                        CiphertextBlob=bytes(
                                            base64.b64decode(cipher_text)))
    except ClientError:
        logger.exception('Could not decrypt the string.')
        raise
    else:
        return plain_text['Plaintext']

if __name__ == '__main__':
    # Constants
    CIPHER_BLOB = 'AQICAHjCLrve605Q688Og+zdiH0Bw59CmQpIyvxuqwY2CStfxQELu2JC4UClfF5nMdwLX+USAAAAbDBqBgkqhkiG9w0BBwagXTBbAgEAMFYGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM4CElmAK17MXdIFnaAgEQgCkoPqRPMxLYJAOKmYNvlB7J7qpzuITx/x7AWBrx2kn6kZHqzaDKB6iTwQ=='
    KEY_ALIAS = 'alias/hands-on-cloud-kms-alias'
    logger.info('Decrypting...')
    kms = decrypt(CIPHER_BLOB, KEY_ALIAS)
    logger.info(f"Decrypted string: {kms.decode('utf8')}.")

The required argument is:

  • CiphertextBlob: Ciphertext to be decrypted.

The optional argument used in the above example is:

  • KeyIdSpecifies the KMS key to use in the decryption.

The decrypt() method returns the Plaintext of the encrypted Plaintext.

Here is the code execution output:

Decrypt a string using KMS
Decrypt a string using KMS

How to encrypt files using KMS and Boto3 in Python?

You must use the encrypt() and generate_data_key() methods from the Boto3 library.

A data key is generated and associated with the specified KMS key during the file encryption. The generated encrypted data key is stored with the encrypted file. This allows the file to be decrypted by any program with the credentials to decrypt the data key.

The encrypted file is saved to <filename>.encrypted in the same path as the source file.

We also need to use the well-known Python cryptography package to encrypt and decrypt the file data.

The cryptography package can be installed using the below command.

pip install cryptography

import base64
import json
import logging
import boto3
from botocore.exceptions import ClientError
from cryptography.fernet import Fernet
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def create_data_key(key_alias, key_spec='AES_256'):
    """
    Generates a unique symmetric data key for client-side encryption.
    """
    try:
        response = kms_client.generate_data_key(KeyId=key_alias,
                                                KeySpec=key_spec)
    except ClientError as e:
        logging.error(e)
        return None, None
    # Return the encrypted and plaintext data key
    return response['CiphertextBlob'], base64.b64encode(response['Plaintext'])

def encrypt_file(filename, key_alias):
    """
    Encrypts plaintext into ciphertext by using a KMS key.
    """
    # Read the entire file into memory
    try:
        with open(filename, 'rb') as file:
            file_contents = file.read()
    except IOError as e:
        logging.error(e)
        return False
    data_key_encrypted, data_key_plaintext = create_data_key(key_alias)
    if data_key_encrypted is None:
        return False
    logging.info('Created new AWS KMS data key')
    # Encrypt the file
    f = Fernet(data_key_plaintext)
    file_contents_encrypted = f.encrypt(file_contents)
    # Write the encrypted data key and encrypted file contents together
    try:
        with open(filename + '.encrypted', 'wb') as file_encrypted:
            file_encrypted.write(
                len(data_key_encrypted).to_bytes(NUM_BYTES_FOR_LEN,
                                                 byteorder='big'))
            file_encrypted.write(data_key_encrypted)
            file_encrypted.write(file_contents_encrypted)
    except IOError as e:
        logging.error(e)
        return False
    except ClientError:
        logger.exception('Could not encrypt the file.')
        raise
    else:
        return True

if __name__ == '__main__':
    # Constants
    FILE_NAME = '/home/ec2-user/environment/hands-on-cloud/kms/passwd'
    KEY_ALIAS = 'alias/hands-on-cloud-kms-alias'
    NUM_BYTES_FOR_LEN = 4
    logger.info('Encrypting file...')
    kms = encrypt_file(FILE_NAME, KEY_ALIAS)
    logger.info(f'Encrypted file: {kms}.')

In the above example, we have specified a variable NUM_BYTES_FOR_LEN. This variable specifies the number of bytes used in the encrypted file to store the length of the encrypted data key. 

The above example uses the alias/hands-on-cloud-kms-alias key alias to encrypt the file and generate data kay; then, the file is encrypted using the Python cryptography module. The encrypted file is stored with an encrypted data key with a .encrypted extension.

Here is the code execution output:

File to be encrypted
File to be encrypted
Encrypt a file using KMS
Encryption Code Execution
Encrypted File Contents
Encrypted File Contents

How to decrypt files using KMS and Boto3 in Python?

To decrypt the file, you need to use the decrypt() method from the Boto3 library.

The data key associated with the encrypted file is read and decrypted using the decrypt() method during the file decryption.

The decrypted file is saved with <filename> in the same path as the .encrypted file.

We also need to use the Python cryptography package to decrypt the file content using the data key.

import base64
import json
import logging
import boto3
from botocore.exceptions import ClientError
from cryptography.fernet import Fernet
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def decrypt_data_key(data_key_encrypted):
    """
    Decrypts an encrypted data key.
    """
    # Decrypt the data key
    try:
        response = kms_client.decrypt(CiphertextBlob=data_key_encrypted)
    except ClientError as e:
        logging.error(e)
        return None
    # Return plaintext base64-encoded binary data key
    return base64.b64encode((response['Plaintext']))

def decrypt_file(filename):
    """
    Decrypts a file encrypted by encrypt_file() by using a KMS key.
    """
    # Read the encrypted file into memory
    try:
        with open(filename + '.encrypted', 'rb') as file:
            file_contents = file.read()
    except IOError as e:
        logging.error(e)
        return False
    data_key_encrypted_len = int.from_bytes(file_contents[:NUM_BYTES_FOR_LEN],
                                            byteorder='big') \
                             + NUM_BYTES_FOR_LEN
    data_key_encrypted = file_contents[
        NUM_BYTES_FOR_LEN:data_key_encrypted_len]
    # Decrypt the data key before using it
    data_key_plaintext = decrypt_data_key(data_key_encrypted)
    if data_key_plaintext is None:
        logging.error("Cannot decrypt the data key.")
        return False
    # Decrypt the rest of the file
    f = Fernet(data_key_plaintext)
    file_contents_decrypted = f.decrypt(file_contents[data_key_encrypted_len:])
    # Write the decrypted file contents
    try:
        with open(filename, 'wb') as file_decrypted:
            file_decrypted.write(file_contents_decrypted)
    except IOError as e:
        logging.error(e)
        return False
    except ClientError:
        logger.exception('Could not decrypt the file.')
        raise
    else:
        return True

if __name__ == '__main__':
    # Constants
    FILE_NAME = '/home/ec2-user/environment/hands-on-cloud/kms/passwd'
    NUM_BYTES_FOR_LEN = 4
    logger.info('Decrypting file...')
    kms = decrypt_file(FILE_NAME)
    logger.info(f'Decrypted file: {kms}.')

The above example uses the passwd.encrypted file created in the last example, decrypts it, and stores decrypted files in the same path as the original file.

Also, we have used the variable NUM_BYTES_FOR_LEN. This variable specifies the number of bytes used in the encrypted file to store the length of the encrypted data key.

Here is the code execution output:

Decrypt a file
Code Execution for File Decryption
Decrypted File Contents
Decrypted File Contents

How to create a digital signature using KMS and Boto3 in Python?

To create a digital signature using the KMS key, you must use the sign() method from the Boto3 library.

Digital signatures are created and verified using asymmetric KMS key pairs with a KeyUsage value of SIGN_VERIFY. To create an asymmetric KMS key pair with SIGN_VERIFY, we will use the create_key() method, which we previously used. The key ID created by the create_key() method is used to sign a digital signature.

import base64
import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def create_kms_key():
    """
    Creates a unique customer managed KMS key for signature verify.
    """
    try:
        response = kms_client.create_key(Description='hands-on-cloud-sign',
                                         KeyUsage='SIGN_VERIFY',
                                         CustomerMasterKeySpec='RSA_2048',
                                         Tags=[{
                                             'TagKey':
                                             'Name',
                                             'TagValue':
                                             'hands-on-cloud-sign'
                                         }])
    except ClientError:
        logger.exception('Could not create a KMS key for signature verify.')
        raise
    else:
        return response['KeyMetadata']['KeyId']

def create_signature(message):
    """
    Creates a digital signature for a message by using a KMS key.
    """
    try:
        # create a KMS key for signature verify
        key_id = create_kms_key()
        # encrypt the messsage signature
        sign = kms_client.sign(KeyId=key_id,
                               Message=message,
                               SigningAlgorithm='RSASSA_PSS_SHA_256')
    except ClientError:
        logger.exception('Could not create the digital signature.')
        raise
    else:
        return sign

if __name__ == '__main__':
    # Constants
    MESSAGE = 'hands-on-cloud'
    logger.info('Creating a digital signature...')
    kms = create_signature(MESSAGE)
    logger.info(
        f'Digital signature: {base64.b64encode(kms["Signature"]).decode()}')

The required arguments are:

  • KeyIdSpecifies the KMS key to use in the encryption.
  • Message: Specifies the message to sign.
  • SigningAlgorithm: Specifies the algorithm to use when signing the message. To get all the available algorithms, refer here.

The above example creates a digital signature for a message string ‘hands-on-cloud’.

Also, note that we use the base64.b64encode method to parse the BASE64 output of the sign() method.

Here is the code execution output:

Create a digital signature using KMS
Create a digital signature using KMS

How to verify a digital signature using KMS and Boto3 in Python?

To verify a digital signature using the KMS key, you must use the verify() method from the Boto3 library.

Verifying a digital signature confirms that an authorized user signed the message with the specified KMS key and signing algorithm. The message hasn’t been tampered with since the authorized user signed it.

import base64
import json
import logging
import boto3
from botocore.exceptions import ClientError
AWS_REGION = 'us-east-2'
# logger config
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s: %(levelname)s: %(message)s')
kms_client = boto3.client("kms", region_name=AWS_REGION)

def verify_signature(key_id, message, signature):
    """
    Verifies a digital signature that was generated by the Sign operation.
    """
    try:
        # verify the messsage signature
        sign = kms_client.verify(KeyId=key_id,
                                 Message=bytes(message, 'utf-8'),
                                 Signature=bytes(base64.b64decode(signature)),
                                 SigningAlgorithm='RSASSA_PSS_SHA_256')
    except ClientError:
        logger.exception('Could not verify the digital signature.')
        raise
    else:
        return sign

if __name__ == '__main__':
    # Constants
    KEY_ID = '797cd45e-cd93-41f8-9bac-fbb89cf95e5f'
    MESSAGE = 'hands-on-cloud'
    SIGNATURE = 'SCoSGKjubYjdFXF+00L3a7kC9EJAEtZG4Z+yUzF1P3a9cp/hBBUWMnd69GLZShnSOcHCqQcWsqQMYrJufC2lUR7veapeTtlFIU1/5aeML9z4V/F2PeefrhyjvidEDfJhmfdAGXhmUbz5eakeWBZDe4tdM1jAYYCtW87KmKWg2pG8WUgRx4yGnalI0EYCk+By6dBbWTgAj8rEebjuJplAPcz3XbZFhiANRhN8/1Ryoq1aJD+PC7reEl+Cs+G7gURhestbbN9WuNjAT5TO2L+ZOIXd7SWI4bXQg7kPoM0nuewQG39rCrczRbeupeURnCmSRWONG1rpIPWnmYjHYrV2pw=='
    logger.info('Verifying a digital signature...')
    kms = verify_signature(KEY_ID, MESSAGE, SIGNATURE)
    logger.info(f'Digital signature verified: {kms["SignatureValid"]}.')

The required arguments are:

  • KeyIdSpecifies the KMS key to use in the encryption.
  • Message: Specifies the message to sign.
  • SignatureSpecifies the signature that the Sign operation generated.
  • SigningAlgorithm: Specifies the algorithm to use when signing the message. To get all the available algorithms, refer here.

The above example verifies the digital signature for a message string ‘hands-on-cloud‘ created in the previous example.

Also, note that we use the base64.b64decode method to decode the BASE64 output of the sign() method.

Here is the code execution output:

Verify a digital signature using KMS
Verify a digital signature using KMS

Summary

This article covered the essential details of Amazon Key Management Service using the Boto3 library in Python. We’ve also described how to create, enable, disable, list, and describe KMS keys, aliases, and grants. Also, we covered some of the real-world applications of KMS encryption-decryption using the Boto3 library.