Skip to content

credctl: Eliminating Plaintext Cloud Keys with the Secure Enclave

Here’s a number that should keep you up at night: 86% of breaches involve stolen credentials. In 2025 alone, infostealer malware exfiltrated 1.8 billion credentials from 5.8 million devices — an 800% surge over recent years.

And where are your cloud credentials right now?

If you’re like most developers, the answer is ~/.aws/credentials. A plaintext file. On your laptop. Readable by any process running as your user.

[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

That file is the single most common credential pattern in cloud computing. It never expires. It works from any machine. And it can be stolen by any malware with file access, copied from disk images, committed to dotfile repos, or extracted from a stolen laptop.

Think about what that means in practice. You install a VS Code extension, a Homebrew package, or a Python library — any of them could read ~/.aws/credentials silently. You back up your disk, and those keys are in the backup. You sell your old laptop and don’t wipe it properly, and those keys go with it. You share your dotfiles on GitHub and accidentally include your credentials directory.

The breach data tells the same story, over and over:

  • CircleCI (2023): Malware on a developer laptop exfiltrated a session cookie. The attacker accessed production systems and forced all customers to rotate their secrets.
  • LastPass (2022): A developer workstation was compromised. Credentials from the first breach were used to access cloud storage containing customer vault backups. The result was one of the most catastrophic data breaches in password manager history.
  • Okta (2023): A stolen service account credential, stored in a personal Google account synced from a company device, gave attackers access to every customer’s support case files.
  • Uber (2022): Stolen contractor credentials combined with MFA fatigue bombing compromised internal systems. The former CISO was criminally convicted.
  • Codecov (2021): A modified CI script exfiltrated environment variables — including credentials — from thousands of downstream customers.

Every one of these traces back to the same pattern: long-lived credentials accessible on a developer machine. The attackers aren’t breaking encryption or exploiting zero-days. They’re reading files.

Here’s what’s strange. Your Mac has had a Secure Enclave since 2016. It’s a hardware security module — a dedicated chip that generates cryptographic keys, stores them in hardware, and never allows them to be exported. The private key physically cannot leave the chip. Not by malware, not by root access, not by forensic disk imaging.

Your Mac uses the Secure Enclave for Touch ID, Apple Pay, and FileVault. Banks use it. Governments use it. Apple’s corecrypto module is FIPS 140-2 validated.

Meanwhile, AWS has supported OIDC federation since 2014. Any service that can produce a signed JWT can exchange it for short-lived STS credentials via AssumeRoleWithWebIdentity. No long-lived keys required.

The Secure Enclave can sign JWTs. AWS can accept them. Nothing connected the two.

That’s the gap credctl fills.

credctl uses your Mac’s Secure Enclave to replace long-lived cloud access keys with short-lived, hardware-bound credentials. It works with both AWS and GCP today, with Azure on the roadmap.

The private key lives in the Secure Enclave — it can never be exported, copied, or stolen. When you need AWS credentials, credctl signs a JWT with that hardware-bound key and exchanges it for short-lived STS credentials via OIDC federation. The credentials last one hour. There’s nothing on disk to steal.

$ credctl init
✓ Generated ECDSA P-256 key pair in Secure Enclave
✓ Exported public key to ~/.credctl/device.pub
✓ Device ID: SHA256:oKz3i9Tg...
$ credctl setup aws --policy-arn arn:aws:iam::123456789012:policy/DevAccess
✓ Deployed CloudFormation stack (S3, CloudFront, OIDC provider, IAM role)
✓ OIDC issuer URL: https://d1234.cloudfront.net
$ credctl auth
✓ Built JWT (iss=https://d1234.cloudfront.net, sub=SHA256:oKz3i9Tg...)
✓ Signed with Secure Enclave (Touch ID)
✓ Exchanged for STS credentials (expires in 1h)
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...

That’s it. Five minutes from install to working credentials. No server infrastructure. No SSO portal. No browser redirects.

The architecture is straightforward:

sequenceDiagram
participant Dev as Developer
participant CLI as credctl CLI
participant SE as Secure Enclave
participant STS as AWS STS
participant OIDC as OIDC Provider<br/>(S3 + CloudFront)
Dev->>CLI: credctl auth
CLI->>CLI: Build JWT (iss, sub, aud)
CLI->>SE: Sign JWT (ECDSA P-256 / ES256)
SE-->>CLI: Signed JWT
CLI->>STS: AssumeRoleWithWebIdentity
STS->>OIDC: Fetch JWKS (public key)
STS->>STS: Validate signature, assume role
STS-->>CLI: Short-lived credentials (1h)
CLI-->>Dev: AWS credentials
  1. credctl init generates an ECDSA P-256 key pair inside the Secure Enclave. The private key never leaves the hardware. The public key is exported.

  2. credctl setup aws creates an S3 bucket to host OIDC discovery documents, an IAM OIDC identity provider that trusts the issuer URL, an IAM role configured for web identity federation, and configures the AWS CLI profile — all in a single command.

  3. credctl auth builds a JWT with your issuer URL, device ID, and sts.amazonaws.com as the audience. The Secure Enclave signs it (Touch ID prompt). The CLI sends it to STS via AssumeRoleWithWebIdentity. STS fetches your JWKS, validates the signature, and returns short-lived credentials.

The CLI is written in Go. The Secure Enclave integration uses cgo to call Apple’s Security framework directly (SecKeyCreateRandomKey, SecKeyCreateSignature). The STS call is a raw HTTP POST — no AWS SDK dependency. The only external dependency is spf13/cobra for CLI argument parsing.

credctl’s OIDC architecture was designed for cross-cloud portability from the start. The same Secure Enclave key and OIDC provider work with both AWS and GCP.

GCP setup is just as simple:

$ credctl setup gcp --service-account credctl@my-project.iam.gserviceaccount.com
✓ Created Workload Identity Pool
✓ Created OIDC Provider (using existing issuer URL)
✓ Bound service account to device identity
$ credctl setup gcp-cred-file
✓ Wrote credential config to ~/.credctl/gcp-credentials.json
$ export GOOGLE_APPLICATION_CREDENTIALS=~/.credctl/gcp-credentials.json
$ gcloud storage ls

One hardware identity. Two clouds. No keys on disk for either.

To be clear about scope — credctl today is:

  • macOS only. Secure Enclave integration works on Apple Silicon (M1–M4) and Intel Macs with T2 chip. Linux TPM 2.0 support is planned but not yet implemented.
  • AWS and GCP. Azure Federated Identity Credentials are on the roadmap.
  • Individual use. Direct Mode means each developer manages their own OIDC endpoint. A team broker with policy enforcement, audit trails, and device fleet management is planned for a future phase.

credctl doesn’t replace HashiCorp Vault for secrets management. It replaces the plaintext cloud keys on your laptop. Different problem, different tool.

The roadmap expands in concentric circles:

  • Azure: Federated Identity Credentials, completing the three major clouds with one hardware identity.
  • Linux TPM 2.0: The same architecture using TPM 2.0 on Linux workstations. Windows 11 requires TPM 2.0, so the hardware is already there.
  • Credential broker for teams: A centralised broker that sits between developers and cloud providers. Policy enforcement (who can assume which roles, from which devices), approval workflows, and a full audit trail mapped to SOC 2, NIS2, DORA, and ISO 27001 controls.

credctl is open source (Apache 2.0).

Questions and feedback welcome in GitHub Discussions.