PHPackages                             laravel-chronicle/kms-aws - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. laravel-chronicle/kms-aws

ActiveLibrary[Security](/categories/security)

laravel-chronicle/kms-aws
=========================

AWS KMS signing adapter for the Chronicle audit ledger - remote sign, local verify.

1.1.0(1mo ago)10[3 issues](https://github.com/laravel-chronicle/kms-aws/issues)MITPHPPHP ^8.2CI passing

Since Jun 4Pushed 1w ago1 watchersCompare

[ Source](https://github.com/laravel-chronicle/kms-aws)[ Packagist](https://packagist.org/packages/laravel-chronicle/kms-aws)[ GitHub Sponsors](https://github.com/ntoufoudis)[ RSS](/packages/laravel-chronicle-kms-aws/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (14)Versions (4)Used By (0)

laravel-chronicle/kms-aws
=========================

[](#laravel-chroniclekms-aws)

[![Tests](https://github.com/laravel-chronicle/kms-aws/actions/workflows/run-tests.yml/badge.svg)](https://github.com/laravel-chronicle/kms-aws/actions/workflows/run-tests.yml)[![PHPStan](https://github.com/laravel-chronicle/kms-aws/actions/workflows/phpstan.yml/badge.svg)](https://github.com/laravel-chronicle/kms-aws/actions/workflows/phpstan.yml)[![Latest Version](https://camo.githubusercontent.com/bb97b602a363fcf0a3aefdec9ce14cf07b37fa5de58bbc8aa273df30fbb5d46b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c61726176656c2d6368726f6e69636c652f6b6d732d6177732e737667)](https://packagist.org/packages/laravel-chronicle/kms-aws)[![Total Downloads](https://camo.githubusercontent.com/88baa6762db28ad3c05200c68c4440e5c841235e238c8284f6408aa99297ec77/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6c61726176656c2d6368726f6e69636c652f6b6d732d6177732e737667)](https://packagist.org/packages/laravel-chronicle/kms-aws)[![License](https://camo.githubusercontent.com/4245e594ec226ba63e52e64be2fe7d149817d2d1b7dab1fcde0b0bddf705c8c2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6c61726176656c2d6368726f6e69636c652f6b6d732d6177732e737667)](LICENSE)

AWS KMS custody for the [Chronicle audit ledger](https://github.com/laravel-chronicle/core).

Keeps Chronicle's cryptographic key material inside AWS KMS instead of on the application server. The package provides two independent providers:

- **Signing** (`AwsKmsSigningProvider`) - signs checkpoints and exports via KMS (ECDSA P-256). Verification is always **offline**, using a cached public key, so no AWS call is needed to verify.
- **KEK custody** (`KmsKeyEncryptionProvider`) - holds the Key Encryption Key for Chronicle's crypto-shredding, wrapping and unwrapping per-subject DEKs through KMS `Encrypt`/`Decrypt` so the KEK never leaves the HSM.

Use either or both. The signing setup is covered first; KEK custody has its own section below.

---

Installation
------------

[](#installation)

```
composer require laravel-chronicle/kms-aws
```

The package auto-discovers its service provider via Laravel's package discovery.

---

Requirements
------------

[](#requirements)

- PHP 8.2+
- `ext-openssl`
- `laravel-chronicle/core` ^1.10
- AWS SDK for PHP ^3.0

---

AWS Setup
---------

[](#aws-setup)

> This section sets up the **signing** provider. If you also want KEK custody for crypto-shredding, you'll need a separate **symmetric** key - see [KEK encryption provider](#kek-encryption-provider-crypto-shredding) below. The two providers use different key types and are configured independently.

### Create a KMS key (signing)

[](#create-a-kms-key-signing)

Create an asymmetric KMS key with:

- **Key type:** Asymmetric
- **Key spec:** ECC\_NIST\_P256
- **Key usage:** SIGN\_VERIFY

### Required IAM actions

[](#required-iam-actions)

Attach the following IAM policy to the role that runs your application:

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Sign",
        "kms:DescribeKey"
      ],
      "Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/KEY_ID"
    }
  ]
}
```

`kms:GetPublicKey` is **not** required at runtime - the public key is cached in your application config and never fetched from KMS during verification.

### Retrieve and cache the public key

[](#retrieve-and-cache-the-public-key)

Retrieve your KMS key's public key once and store it in your config:

```
aws kms get-public-key \
  --key-id arn:aws:kms:REGION:ACCOUNT_ID:key/KEY_ID \
  --query 'PublicKey' --output text | base64 -d | \
  openssl pkey -pubin -inform DER -outform PEM
```

This outputs a PEM string like:

```
-----BEGIN PUBLIC KEY-----
MFkwEwYH...
-----END PUBLIC KEY-----

```

Store this as the `public_key` in your Chronicle signing config (see below).

---

Configuration
-------------

[](#configuration)

Register the KMS key in `config/chronicle.php` under `signing.keys`:

```
use Chronicle\KmsAws\AwsKmsSigningProvider;

'signing' => [
    'active' => env('CHRONICLE_ACTIVE_KEY', 'kms-production'),

    'keys' => [
        'kms-production' => [
            'provider'   => AwsKmsSigningProvider::class,
            'algorithm'  => 'ecdsa-p256',
            'key_arn'    => env('CHRONICLE_KMS_KEY_ARN'),
            'public_key' => env('CHRONICLE_KMS_PUBLIC_KEY'),  // PEM string
        ],
    ],
],
```

Set the corresponding environment variables:

```
AWS_DEFAULT_REGION=eu-west-1
CHRONICLE_ACTIVE_KEY=kms-production
CHRONICLE_KMS_KEY_ARN=arn:aws:kms:eu-west-1:123456789012:key/your-key-id
CHRONICLE_KMS_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----
"
```

---

How it works
------------

[](#how-it-works)

OperationWhere it runs`sign()`**Remote** - calls KMS `Sign` API with `MessageType: DIGEST``verify()`**Local** - `openssl_verify` against the cached PEM public keyThe private key never leaves AWS KMS. Verification is offline and instant.

---

Key rotation
------------

[](#key-rotation)

Chronicle's key rotation works identically for KMS-backed keys. Retire the old key by keeping only its `public_key` in the ring (omit `key_arn`), then add the new KMS key as active. Historic checkpoints and exports continue to verify offline against the retained public key.

Example two-key ring after rotation:

```
'signing' => [
    'active' => 'kms-2026',
    'keys' => [
        // Retired - switch to EcdsaSigningProvider (from core) for verify-only mode.
        // AwsKmsSigningProvider requires key_arn and cannot be verify-only.
        'kms-2025' => [
            'provider'   => \Chronicle\Signing\EcdsaSigningProvider::class,
            'algorithm'  => 'ecdsa-p256',
            'public_key' => env('CHRONICLE_KMS_2025_PUBLIC_KEY'),
        ],
        // Active
        'kms-2026' => [
            'provider'   => AwsKmsSigningProvider::class,
            'algorithm'  => 'ecdsa-p256',
            'key_arn'    => env('CHRONICLE_KMS_KEY_ARN'),
            'public_key' => env('CHRONICLE_KMS_PUBLIC_KEY'),
        ],
    ],
],
```

> **Note:** `AwsKmsSigningProvider` requires `key_arn` at construction - it cannot be used as a verify-only provider. For retired KMS keys, switch the entry to `Chronicle\Signing\EcdsaSigningProvider` (from core) with only `public_key` set, as shown above. Core's `EcdsaSigningProvider` handles the local-verify-only case.

---

KEK encryption provider (crypto-shredding)
------------------------------------------

[](#kek-encryption-provider-crypto-shredding)

Chronicle v1.12 can encrypt PII payload fields under a per-subject DEK, wrapping those DEKs under a Key Encryption Key (KEK). This package can hold the KEK in AWS KMS so wrapped DEKs are protected outside the application.

Point `chronicle.encryption.kek` at the KMS provider:

```
// config/chronicle.php
use Chronicle\KmsAws\KmsKeyEncryptionProvider;

'encryption' => [
    'enabled' => true,
    'kek' => [
        'provider' => KmsKeyEncryptionProvider::class,
        'key' => env('CHRONICLE_KMS_KEK_ARN'),   // KMS key ARN/id for Encrypt/Decrypt
        'id'  => env('CHRONICLE_KMS_KEK_ID'),     // kekId recorded per subject key
    ],
],
```

Required IAM actions on the KEK: `kms:Encrypt`, `kms:Decrypt`. The `KmsClient` is resolved from the container (region from `AWS_DEFAULT_REGION`), so no extra wiring is needed beyond installing this package.

### KmsClient options

[](#kmsclient-options)

The `KmsClient` singleton is shaped from `config/chronicle-kms.php`. All keys have sensible defaults - set nothing, and you get a standard region-derived client.

```
# Region the KMS client talks to (standard AWS variable)
AWS_DEFAULT_REGION=eu-west-1

# Optional: override the KMS endpoint. Leave unset for normal AWS use.
# Point at LocalStack for testing, or a KMS FIPS endpoint for regulated deployments.
CHRONICLE_KMS_ENDPOINT=http://localhost:4566
# CHRONICLE_KMS_ENDPOINT=https://kms-fips.eu-west-1.amazonaws.com

# Optional: pin the KMS API version (defaults to 'latest')
CHRONICLE_KMS_VERSION=latest
```

Credentials are never read from this config - they flow through the standard AWS credential chain (env vars, IAM roles, etc.). For anything these keys don't cover - a custom credential provider, or a fully custom client - re-bind `Aws\Kms\KmsClient` in your application's `AppServiceProvider`; that binding wins over this provider's default.

---

License
-------

[](#license)

MIT

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance76

Regular maintenance activity

Popularity2

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 89.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Total

2

Last Release

36d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9a0e4562d814e61aaa5dc698cc667c6d6c90c98516142b60c0924b337c418355?d=identicon)[ntoufoudis](/maintainers/ntoufoudis)

---

Top Contributors

[![ntoufoudis](https://avatars.githubusercontent.com/u/93659348?v=4)](https://github.com/ntoufoudis "ntoufoudis (17 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")

---

Tags

laravelawssigningAuditkmsECDSAchronicle

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/laravel-chronicle-kms-aws/health.svg)

```
[![Health](https://phpackages.com/badges/laravel-chronicle-kms-aws/health.svg)](https://phpackages.com/packages/laravel-chronicle-kms-aws)
```

###  Alternatives

[ellaisys/aws-cognito

Laravel Authentication using AWS Cognito (Web and API)

121256.9k1](/packages/ellaisys-aws-cognito)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
