module AWS

aws

AWS for Quarz, written in Quarz over its standard library: credentials (the SDKs' chain), request signing (Signature Version 4, usable for any service), and service clients as modules of this cog, starting with KMS.

# Cog.toml of an application
[dependencies]
AWS = { git = "https://github.com/quarz-lang/aws", tag = "v0.1.0" }

The API reference of the main branch is at https://aws.api.quarz.dev.

Work in progress: the design is issue #1. What exists:

Credentials

creds = AWS::Credentials.default   # a provider: Shareable, cached, refreshed
keys = creds.get                   # AWS::Credentials::Keys
keys.inspect                       # => "#<AWS::Credentials::Keys ASIA... expires 2026-11-07T12:00:00Z>"

Signature Version 4

req = HTTP::Client::Request.post("https://sqs.ap-northeast-1.amazonaws.com/", body: form,
                                 content_type: "application/x-www-form-urlencoded")
signed = AWS::SigV4.sign(req, service: "sqs", region: "ap-northeast-1", credentials: creds.get)
url = AWS::SigV4.presign(HTTP::Client::Request.get("https://bucket.s3.amazonaws.com/key"),
                         service: "s3", region: "us-east-1", credentials: creds.get, expires_in: 15.minutes)
signer = AWS::SigV4::Signer.new("kms", "us-east-1", creds)   # signer.sign(req)

Tested against the official SigV4 test suite (test/fixtures/sigv4/, from awslabs/aws-c-auth, Apache-2.0) at every stage, the S3 documentation's examples, and fake endpoints for every provider.

Configuration

config = AWS::Config.new(region: "ap-northeast-1", credentials: AWS::Credentials.default)
config = AWS::Config.default   # from the environment

AWS::Config(region:, credentials:, endpoint: nil, http: HTTP::Client.default, retries: 3, timeout: 30.seconds, retry_base: 100.milliseconds, retry_cap: 20.seconds, service_endpoints: {}): the region, the credentials provider, an endpoint for every service (a local emulator) or one per service, the HTTP client, the retries (full-jitter backoff up to min(retry_cap, retry_base * 2**n)) and the longest an attempt may take. Config.default reads AWS_REGION, AWS_DEFAULT_REGION or the profile's region, Credentials.default, AWS_ENDPOINT_URL and AWS_ENDPOINT_URL_<SERVICE> (AWS_ENDPOINT_URL_KMS).

KMS

kms = AWS::KMS.new(config)   # Shareable: one per program

out = kms.encrypt(key_id: "alias/app", plaintext: secret, encryption_context: {"tenant" => "t1"})
kms.decrypt(ciphertext_blob: out.ciphertext_blob, encryption_context: {"tenant" => "t1"}).plaintext

dk = kms.generate_data_key(key_id: "alias/app", key_spec: :aes_256)   # dk.plaintext, dk.ciphertext_blob
sig = kms.sign(key_id: "alias/sign", message: bytes, signing_algorithm: :rsassa_pkcs1_v1_5_sha_256).signature
kms.verify(key_id: "alias/sign", message: bytes, signature: sig, signing_algorithm: :rsassa_pkcs1_v1_5_sha_256)   # => Bool
pub = kms.get_public_key(key_id: "alias/sign")                 # pub.public_key: DER, Crypto::RSA::PublicKey.from_der
kms.describe_key(key_id: "alias/app").enabled?
kms.generate_random(number_of_bytes: 32).plaintext

box = AWS::KMS::Envelope.new(kms, "alias/app", {"tenant" => "t1"})
sealed = box.seal(large_secret)   # Bytes: a data key from KMS, AES-256-GCM
box.open(sealed)

Errors

Not there yet

Other services (S3, SQS, STS beyond the credentials), presigned S3 uploads beyond SigV4.presign itself, a data-key cache for KMS::Envelope.

Tests

quarz test runs against fake endpoints (a fake KMS in Quarz that recomputes each request's signature) and temporary files. An opt-in test against a real KMS reads AWS_TEST_KMS_KEY_ID (a symmetric key the environment's credentials may use; AWS_ENDPOINT_URL_KMS for a local emulator) and is never run in CI.

License

MIT No Attribution (LICENSE).

Classes and modules