# AliCloud Private CA Issuer for cert-manager

This repository contains a [cert-manager](https://cert-manager.io) external issuer that integrates with [AliCloud Private Certificate Authority (Private CA)](https://www.alibabacloud.com/product/certificate-authority-service). The controller is responsible for creating and polling AliCloud Private CA certificates on behalf of `CertificateRequest` resources and surfacing their state back to cert-manager.

## Features

- **Namespace & Cluster Scope** – Implements both `AliCloudPCAIssuer` and `AliCloudPCAClusterIssuer` custom resources (group `alicloudpca.cert-manager.io`).
- **Automatic Approval** – Ships a dedicated controller that auto-approves `CertificateRequest` objects referencing this issuer group.
- **Async-Safe Signing** – Handles AliCloud's asynchronous issuance flow using a pending marker plus CSR fingerprinting to deduplicate retries and resume in-flight requests.
- **Health Checks with Error Classification** – Performs readiness probes against the backing CA and uniquely classifies permanent AliCloud errors to avoid noisy retries.
- **Credential Flexibility** – Uses AliCloud's default credential chain (environment variables, instance/role metadata, etc.) and optionally assumes a RAM role per issuer via STS.

### Required AliCloud Permissions

```json
{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "yundun-cert:CreateServerCertificateWithCsr",
        "yundun-cert:DescribeCACertificate",
        "yundun-cert:DescribeClientCertificate"
      ],
      "Resource": "*"
    }
  ]
}
```

## Usage

### 1. Provide AliCloud Credentials

The controller relies on [aliyun/credentials-go](https://github.com/aliyun/credentials-go) with its default provider chain. Common options include:

- Exporting `ALICLOUD_ACCESS_KEY_ID`, `ALICLOUD_ACCESS_KEY_SECRET`, and optionally `ALICLOUD_SECURITY_TOKEN`.
- Running inside an ECS instance, ACK node, or Pod with a bound RAM role.
- Supplying `AssumeRole` configuration per issuer (see below) to jump into a different account.

### 2. Create an `AliCloudPCAIssuer`

```yaml
apiVersion: alicloudpca.cert-manager.io/v1alpha1
kind: AliCloudPCAIssuer
metadata:
  name: my-issuer
  namespace: default
spec:
  caIdentifier: "12345678-1234-1234-1234-123456789012"
  region: "cn-hangzhou"
  assumeRole:
    roleARN: "acs:ram::123456789012:role/cross-account-issuer"
    externalID: "optional-external-id"
    roleSessionName: "issuer-session"
```

### 3. Issue a Certificate

```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-cert
  namespace: default
spec:
  secretName: example-cert-tls
  dnsNames:
    - example.com
    - www.example.com
  issuerRef:
    group: alicloudpca.cert-manager.io
    kind: AliCloudPCAIssuer
    name: my-issuer
```

The bundled approver reconciles `CertificateRequest` objects for this issuer group and grants the `Approved` condition automatically.

## Known Limitations

- Secret-based credential sourcing is not yet implemented; rely on environment metadata or STS AssumeRole.
- Provisioner instances are kept in-memory and are not garbage-collected when an issuer is deleted (restart the controller to reclaim them).
- Release manifests/Helm charts are not available; you must package the deployment yourself.
