parlel/acm

A zero-dependency, in-process fake of AWS Certificate Manager (ACM). Speaks the AWS JSON 1.1 wire protocol (X-Amz-Target: CertificateManager.<Op>), so the AWS SDK for ACM (@aws-sdk/client-acm, boto3, AWS CLI aws acm ...) works against it unmodified — request a certificate, describe it, list, get the PEM, tag, import, and delete.

PropertyValue
Service nameacm
Port4731
ProtocolAWS JSON 1.1 (POST /)
TargetCertificateManager.<Operation>
HealthcheckGET /_parlel/health
Account ID000000000000

Quick start

AWS_ENDPOINT_URL=http://127.0.0.1:4731
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=parlel
AWS_SECRET_ACCESS_KEY=parlel
import { ACMClient, RequestCertificateCommand, DescribeCertificateCommand } from "@aws-sdk/client-acm";

const acm = new ACMClient({
  region: "us-east-1",
  endpoint: "http://127.0.0.1:4731",
  credentials: { accessKeyId: "parlel", secretAccessKey: "parlel" },
});

const { CertificateArn } = await acm.send(new RequestCertificateCommand({ DomainName: "example.com" }));
const { Certificate } = await acm.send(new DescribeCertificateCommand({ CertificateArn }));
console.log(Certificate.Status); // ISSUED

Implemented operations

OperationNotes
RequestCertificateAuto-issues (Status: ISSUED) with DNS validation records. Returns { CertificateArn }.
ImportCertificateImports a cert (Certificate + PrivateKey required); Type: IMPORTED.
DescribeCertificateReturns full CertificateDetail + DomainValidationOptions.
ListCertificatesCertificateStatuses filter; MaxItems + NextToken pagination.
GetCertificateReturns a synthetic PEM body + chain (Certificate, CertificateChain).
DeleteCertificateRemoves the certificate.
AddTagsToCertificateMerge tags onto a certificate.
RemoveTagsFromCertificateRemove tags by key.
ListTagsForCertificateList tags ({ Tags: [{ Key, Value }] }).
ResendValidationEmailValidates Domain/ValidationDomain; empty body on success.
UpdateCertificateOptionsUpdates certificate transparency logging preference.

Each requested certificate includes a DomainValidationOptions entry per domain/SAN with a DNS validation ResourceRecord (CNAME -> acm-validations.aws). Imported certificates carry no DomainValidationOptions (ACM does not domain-validate imports).

Access via MCP / preview URL

When run inside parlel, ACM is reachable through the pool's MCP bridge and any assigned preview URL. Point AWS_ENDPOINT_URL at the preview URL.

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

AreaStatusDetail
Request / Describe / List / Get / Delete certificateWire-faithful AWS JSON 1.1 request + response shapes.
Import certificateType: IMPORTED; requires Certificate + PrivateKey.
Tag operations (Add / Remove / List)Exact { Tags: [{ Key, Value }] } shape.
ListCertificates paginationMaxItems + opaque NextToken honored.
Error envelope + status codes__type / x-amzn-errortype; 400/404; ResourceNotFound, InvalidArn, Validation, UnknownOperation.
SigV4 authenticationAccepted but not verified (dummy parlel creds work).
DNS / email domain validationCerts auto-issue (ISSUED); no real DNS/email round-trip.
PEM materialGetCertificate returns a placeholder PEM, not a real X.509.
Managed renewal / RenewCertificate / ExportCertificateNot modeled.
StateIn memory, cleared on reset.

Error codes & shapes

Errors use the AWS JSON 1.1 envelope: HTTP status + x-amzn-errortype header + { "__type": "<Code>", "message": "..." } body.

ScenarioStatus__type
Certificate ARN not found400ResourceNotFoundException
Missing required CertificateArn400ValidationException
Malformed certificate ARN400InvalidArnException
Missing DomainName on RequestCertificate400ValidationException
Missing Certificate/PrivateKey on import400ValidationException
Unknown X-Amz-Target action404UnknownOperationException

Manifest

{
  "name": "acm",
  "port": 4731,
  "protocol": "http",
  "healthcheck": "/_parlel/health",
  "env_vars": {
    "AWS_ACCESS_KEY_ID": "parlel",
    "AWS_SECRET_ACCESS_KEY": "parlel",
    "AWS_REGION": "us-east-1",
    "AWS_ENDPOINT_URL": "http://127.0.0.1:4731"
  }
}
<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

AWS_ACCESS_KEY_ID=parlel
AWS_SECRET_ACCESS_KEY=parlel
AWS_REGION=us-east-1
AWS_ENDPOINT_URL=http://parlel-bridge:4731
<!-- parlel:testenv:end -->