Post-Image

Keeping Secure: QLDB Basics

Quantum Ledger Database (QLDB) is Amazon Web Service’s commercial Ledger Database. Fundamentally a document storage database, it differentiates itself from other cloud-based document databases by integrating blockchain technology to offer an immutable transaction history and non-repudiation in the form of Merkle tree hash verification. It has other unique qualities, such as the ability to query it natively as if it were a relational database with the PartiQL language, the ability to stream its transaction records to other databases and services with Kinesis, and more.

This will be the first in a series of articles about the different options to secure the service. Today I am going to go over the built in controls AWS provides with the usual suspects of IAM, KMS, AWS PrivateLink, CloudWatch, CloudTrail and AWS Config.

I will be examining this through the lens of the security pillar of AWS’s Well Architected Framework with the following principals in mind:

Let’s get started!



Identity and Access Management

The first area I want to dive into is IAM. As with every AWS deployment, you should ensure that you are using MFA to access your AWS accounts, and use IAM Roles with the principle of least privilege instead of IAM Users.

Built-In roles

Let’s take a look at what policies AWS provides by default for QLDB, and some scenarios where they might be useful.

Spoilers

There aren’t many…

AmazonQLDBReadOnly

Description: Provides read only access to Amazon QLDB.

This built-in policy allows a principal to view Ledger details, journal export and stream details for all ledgers in the account. It also allows a principal to verify a document in the ledger. Note that this permission set does not provide the SendCommand permission, so while you can do the verification, you will need to have the details (Document ID, Block address and Digest information) provided beforehand.

This is potentially a policy that can be provided to a service or user that does verification of documents, with the caveat that the verification process displays the PartiQL statement that created the document. This may surface some confidential information.

Additionally, this policy grants access to all ledgers, so it may be better, depending on your use case, to create a custom policy that is scoped to a specific ledger instead of “*”.

AmazonQLDBReadOnly IAM Policy
{
  "Version": "2012-10-17",
  "Statement": [
      {
        "Effect": "Allow",
        "Action": [
          "qldb:ListLedgers",
          "qldb:DescribeLedger",
          "qldb:ListJournalS3Exports",
          "qldb:ListJournalS3ExportsForLedger",
          "qldb:DescribeJournalS3Export",
          "qldb:DescribeJournalKinesisStream",
          "qldb:ListJournalKinesisStreamsForLedger",
          "qldb:GetBlock",
          "qldb:GetDigest",
          "qldb:GetRevision",
          "qldb:ListTagsForResource"
        ],
        "Resource": "*" <-- PSST! This really is not ideal if you don't need it
      }
  ]
}

AmazonQLDBFullAccess

Description: Provides full access to Amazon QLDB via the service API.

This built-in policy allows a principal to perform most QLDB actions on any resource in an account. This is a very powerful policy and should be restricted to individuals in administrative roles or for exploratory purposes while first getting accustomed to QLDB in a sandbox or development environment.

One thing to note about this policy is that while it grants permissions to stream journals to Kinesis, it doesn’t provide any access to create the stream.

AmazonQLDBFullAccess IAM Policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "qldb:CreateLedger",
                "qldb:UpdateLedger",
                "qldb:UpdateLedgerPermissionsMode",
                "qldb:DeleteLedger",
                "qldb:ListLedgers",
                "qldb:DescribeLedger",
                "qldb:ExportJournalToS3",
                "qldb:ListJournalS3Exports",
                "qldb:ListJournalS3ExportsForLedger",
                "qldb:DescribeJournalS3Export",
                "qldb:CancelJournalKinesisStream",
                "qldb:DescribeJournalKinesisStream",
                "qldb:ListJournalKinesisStreamsForLedger",
                "qldb:StreamJournalToKinesis",
                "qldb:GetDigest",
                "qldb:GetRevision",
                "qldb:GetBlock",
                "qldb:TagResource",
                "qldb:UntagResource",
                "qldb:ListTagsForResource",
                "qldb:SendCommand",
                "qldb:PartiQLCreateTable",
                "qldb:PartiQLCreateIndex",
                "qldb:PartiQLDropTable",
                "qldb:PartiQLDropIndex",
                "qldb:PartiQLUndropTable",
                "qldb:PartiQLDelete",
                "qldb:PartiQLInsert",
                "qldb:PartiQLUpdate",
                "qldb:PartiQLSelect",
                "qldb:PartiQLHistoryFunction",
                "qldb:PartiQLRedact"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": "qldb.amazonaws.com"
                }
            }
        }
    ]
}

AmazonQLDBConsoleFullAccess

Description: Provides full access to Amazon QLDB via the AWS Management Console.

This policy is identical to the AmazonQLDBFullAccess policy with the added permissions of granting access to the Recent and Saved queries in the console. As such, the same recommendation applies here: only give this permission to administrators and for sandbox/exploratory purposes.

Like the previous policy, this also lacks the ability to create data streams.

AmazonQLDBFullAccess IAM Policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "qldb:CreateLedger",
                "qldb:UpdateLedger",
                "qldb:UpdateLedgerPermissionsMode",
                "qldb:DeleteLedger",
                "qldb:ListLedgers",
                "qldb:DescribeLedger",
                "qldb:ExportJournalToS3",
                "qldb:ListJournalS3Exports",
                "qldb:ListJournalS3ExportsForLedger",
                "qldb:DescribeJournalS3Export",
                "qldb:CancelJournalKinesisStream",
                "qldb:DescribeJournalKinesisStream",
                "qldb:ListJournalKinesisStreamsForLedger",
                "qldb:StreamJournalToKinesis",
                "qldb:GetBlock",
                "qldb:GetDigest",
                "qldb:GetRevision",
                "qldb:TagResource",
                "qldb:UntagResource",
                "qldb:ListTagsForResource",
                "qldb:SendCommand",
                "qldb:ExecuteStatement",
                "qldb:ShowCatalog",
                "qldb:InsertSampleData",
                "qldb:PartiQLCreateTable",
                "qldb:PartiQLCreateIndex",
                "qldb:PartiQLDropTable",
                "qldb:PartiQLDropIndex",
                "qldb:PartiQLUndropTable",
                "qldb:PartiQLDelete",
                "qldb:PartiQLInsert",
                "qldb:PartiQLUpdate",
                "qldb:PartiQLSelect",
                "qldb:PartiQLHistoryFunction",
                "qldb:PartiQLRedact"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "dbqms:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kinesis:ListStreams",
                "kinesis:DescribeStream"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": "qldb.amazonaws.com"
                }
            }
        }
    ]
}


Data Protection and Encryption

QLDB is integrated with KMS to allow you to encrypt your ledgers.

Data at Rest

All data in Amazon QLDB is encrypted at rest by default with KMS and cannot be disabled.

On Ledger creation, you can choose an AWS owned key or a Customer Managed Key (CMK). After creation, you can freely swap between using an AWS owned key and a CMK. Server-side encryption is transparent, so this can be done at any time without the need to update the application.

Data in transit

Amazon QLDB only accepts HTTPS requests.

Ledger and Table Protection/Encryption

The way QLDB uses KMS will inform your key usage strategy and ledger design, so it’s important to keep in mind it’s limitations.

Ledgers

KMS keys can only be applied on a Ledger, not a Table. If you have multiple clients or use different customer managed KMS keys for different domains of your business, implement and maintain data segregation by creating separate ledgers for each key.

Tables

While you can’t apply a KMS key to a table, you can tag them. This can be combined with conditional policies on the IAM roles that access the tables to create a data classification layer of security.

For example, consider a situation where an IAM role necessarily has permission to the KMS key, but you don’t want the users of the role to access a protected table containing credit card information. While you could scope the IAM role permissions to exclude that specific table from the permissions policy, you could also create a data classification tag of confidential on the credit card table and deny the role permissions to perform any QLDB actions on any tables tagged with the confidential data classification. We will go more in depth on this concept in a later article.

Customer Managed Key policies

If using a CMK, you will be required to add a key policy that grants permissions for the QLDB service to perform actions on the key. Below is an example key policy that will accomplish this.

CMK Policy
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid" : "Allow access to principals authorized to use Amazon QLDB",
          "Effect" : "Allow",
          "Principal" : {
              "AWS" : "*"
          },
          "Action" : [
              "kms:DescribeKey",
              "kms:CreateGrant"
          ],
          "Resource" : "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
          "Condition" : {
              "StringEquals" : {
                  "kms:ViaService" : "qldb.us-east-1.amazonaws.com",
                  "kms:CallerAccount" : "111122223333"
              }
          }
      }
  ]
}

If the ledger is encrypted with a CMK and that key is deleted, the ledger will be unrecoverable permanently.



Network Security

Amazon QLDB can only be interacted with via API calls to the Amazon network. QLDB is a managed service, and as such the infrastructure and network security configuration options are limited.

Permissions Modes

The permissions mode that is configured on the Ledger determines the actions that an IAM principal can perform over the API. Amazon QLDB has two permissions modes: ALLOW_ALL and STANDARD.

ALLOW_ALL

ALLOW_ALL is a legacy permissions mode. It permits users with SendCommand permissions to perform any PartiQL statements on any tables in the ledger that is specified by the permissions policy. It is not recommended to use this anymore as it’s an all or nothing setting with no option for granularity.

STANDARD

STANDARD is a permissions mode that implicitly denies access to actions and tables in a ledger. It allows for granular access to ledgers, tables and PartiQL actions.

AWS PrivateLink endpoints are available for QLDB. This ensures that all traffic to QLDB is routed within the AWS network and allows any instances or services within your VPC that require access to QLDB to remain private.

The only supported API action through the endpoint is the SendCommand and PartiQL statement actions. You cannot manage the control plane of the service through a PrivateLink interface endpoint.

FIPS Endpoints

FIPS endpoints are available for QLDB and have the same restrictions (can only use SendCommand action) as regular PrivateLink endpoints. They are not widely available - see this link for details on which regions support regular and FIPS endpoints.

Endpoint Policy

Using an endpoint policy, you control what actions can be sent to your QLDB Ledger through the endpoint. Combined with an IAM policy that forces actions on the Ledger to be performed via the endpoint, this is potentially a very powerful control mechanism - it allows for the ability to blanket permit or deny actions to all roles that use QLDB with one policy.

Below is an example of an endpoint policy that:

  1. Allows the SendCommand action through the endpoint to the specified ledger
  2. Gives Read-Only access to all tables on the ledger
Read-Only Endpoint IAM Policy
{
  "Statement": [
    {
      "Sid": "QLDBSendCommandPermission",
      "Principal": "*",
      "Effect": "Allow",
      "Action": "qldb:SendCommand",
      "Resource": "arn:aws:qldb:us-east-1:123456789012:ledger/myExampleLedger"																				
    },
    {
      "Sid": "QLDBPartiQLReadOnlyPermissions",
      "Principal": "*",
      "Effect": "Allow",
      "Action": [
          "qldb:PartiQLSelect",
          "qldb:PartiQLHistoryFunction"
      ],
      "Resource": [
          "arn:aws:qldb:us-east-1:123456789012:ledger/myExampleLedger/table/*",
          "arn:aws:qldb:us-east-1:123456789012:ledger/myExampleLedger/information_schema/user_tables"
      ]
    }
  ]
}



Monitoring and logging

Use CloudWatch to monitor database performance and use CloudTrail to record API calls made to your Ledgers. QLDB does not log transactional API calls to CloudTrail, so none of the PartiQL actions will appear in your CloudTrail logs. This means that to detect anomalous activity on your database, you will need to build some logic into your app.

Monitoring

AWS recommends the following metrics to monitor on a QLDB deployment:

  • Read and write I/Os and storage, so that you can track your ledger’s consumption patterns for billing purposes.
  • Command latency, so that you can track your ledger’s performance when running data operations.
  • Exceptions, so that you can determine whether any requests resulted in an error.

Logging

As we can only monitor Ledger actions, you are limited to logging resource management tasks. Of these actions, the ones of concern for this article are the actions related to exporting of a Ledger’s journal. The journal contains the transactional history of the Ledger, and is very important to track all API calls that perform this to detect data exfiltration.

The actions are:

  • ExportJournalToS3
  • DescribeJournalS3Export
  • ListJournalS3ExportsForLedger
  • ListJournalS3Exports

AWS Config

AWS Config creates a resource for your ledger automatically. At the time of writing this article, there are no AWS Managed rules pertaining to QLDB.



Backup and Recovery

QLDB is a fully managed service, and currently there is currently no built-in function to manually backup and restore your QLDB Ledgers. It is possible to export your Journal which can be imported to a new Ledger to create a copy, but it will be missing the original timestamps and not be a true backup of the original data.



Conclusions

So far we have discussed the built in options that AWS provides to secure QLDB:

  • We can restrict which actions our users and services can perform against our QLDB infrastructure using IAM.
  • We can encrypt the data using KMS, and AWS by default encrypts the data and forces interaction with the service through a secure HTTPS connection.
  • We can control the flow of traffic to QLDB by utilizing PrivateLink endpoints to not only ensure that QLDB traffic remains private, but what actions can be performed through the endpoint.
  • We can monitor performance with CloudWatch and log API requests to the QLDB ledger with CloudTrail.
  • Finally, while there is no built-in functionality to backup and restore our QLDB ledgers manually, AWS provides an export of the data which could be used to re-create the Ledger.

Over the next few articles I will go in-depth on these topics. So check back often or follow Keep Secure’s twitter or linkedin profiles to get notified when my next article is released.

 

About Tyler Fougere

Tyler is an AWS Certified Solutions Architect and has over a decade of enterprise systems administration experience, bringing a wealth of knowledge on Windows, Linux and MacOS infrastructure. You can find him most days and nights trying to quench an insatiable thirst for knowledge of all things cloud and technology.

Share This Article

Comments