acme

package
v0.0.0-...-9799c8d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 2, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package acme provides ACME client functionality for automated certificate management

Package acme provides ACME client functionality for automated certificate management.

Overview

The acme package implements an ACME (Automatic Certificate Management Environment) client using the lego library. It handles certificate lifecycle management including account creation, certificate issuance, renewal, and storage for use with TLS servers.

Key features:

  • Automatic account registration with ACME servers
  • HTTP-01 and TLS-ALPN-01 challenge support
  • Certificate renewal with configurable lead time
  • Persistent storage of accounts and certificates
  • Support for private ACME servers (step-ca, etc.)

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         ACME Client                                 │
├─────────────────────────────────────────────────────────────────────┤
│  Account Management   │  Certificate Ops    │  Storage              │
│  - Registration       │  - Obtain           │  - account.json       │
│  - Key storage        │  - Renew            │  - account.key        │
│                       │  - RenewalLoop      │  - certificate.pem    │
│                       │                     │  - certificate.key    │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│                      ACME Server (CA)                               │
│  Let's Encrypt / step-ca / ZeroSSL / etc.                           │
└─────────────────────────────────────────────────────────────────────┘

Usage

Create an ACME client and obtain a certificate:

cfg := acme.Config{
    DirectoryURL:  "https://acme-v02.api.letsencrypt.org/directory",
    Email:         "[email protected]",
    Domains:       []string{"example.com", "www.example.com"},
    ChallengeType: "http-01",
    RenewBefore:   24 * time.Hour,
    StoragePath:   "/etc/ssl/acme",
}

client, err := acme.NewClient(cfg)
if err != nil {
    log.Fatal(err)
}

// Obtain certificate
cert, err := client.ObtainCertificate(ctx)
if err != nil {
    log.Fatal(err)
}

Check and renew if needed:

cert, renewed, err := client.RenewCertificateIfNeeded(ctx)
if err != nil {
    log.Fatal(err)
}
if renewed {
    log.Println("Certificate was renewed")
}

Background renewal loop:

err := client.StartRenewalLoop(ctx, 1*time.Hour, func(cert *tls.Certificate) {
    // Hot-reload certificate in TLS server
    tlsConfig.Certificates = []tls.Certificate{*cert}
})

Configuration

Config fields:

DirectoryURL   string         // ACME server directory URL (required)
Email          string         // Contact email for account (required)
Domains        []string       // Domains for certificate (required)
ChallengeType  string         // "http-01" or "tls-alpn-01" (default: "http-01")
RenewBefore    time.Duration  // Renew this long before expiry (default: 8h)
StoragePath    string         // Directory for storing certs/keys (required)
CABundle       string         // Optional CA bundle for private ACME servers

Challenge Types

HTTP-01 Challenge:

  • Requires port 80 accessible
  • ACME server makes HTTP request to validate domain
  • Easier to set up, works through most proxies

TLS-ALPN-01 Challenge:

  • Requires port 443 accessible
  • ACME server validates via TLS handshake
  • Better for environments where only TLS port is exposed

Storage

The client stores credentials in the configured StoragePath:

{StoragePath}/account.json   - Account metadata and registration
{StoragePath}/account.key    - Account private key (ECDSA P-256)
{StoragePath}/certificate.pem - Certificate chain (PEM)
{StoragePath}/certificate.key - Certificate private key (PEM)

File permissions are set to 0600 (keys) and 0644 (certificates).

Private ACME Servers

For private ACME servers like step-ca, specify CABundle:

cfg := acme.Config{
    DirectoryURL: "https://ca.internal:9000/acme/acme/directory",
    CABundle:     "/etc/ssl/step-ca-root.pem",
    // ...
}

The CABundle is used to validate the ACME server's TLS certificate.

Thread Safety

The Client is safe for concurrent use. Certificate operations are serialized internally.

Error Handling

Errors are classified using the errs package:

  • Invalid config: errs.WrapInvalid (bad URL, missing required fields)
  • Fatal errors: errs.WrapFatal (file system errors, key generation)
  • Transient errors: errs.WrapTransient (network issues, ACME server errors)

Transient errors during renewal are logged but don't crash the service.

See Also

Related packages:

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Account

type Account struct {
	Email        string                 `json:"email"`
	Registration *registration.Resource `json:"registration"`
	// contains filtered or unexported fields
}

Account represents ACME account registration

func (*Account) GetEmail

func (a *Account) GetEmail() string

GetEmail returns the account email address

func (*Account) GetPrivateKey

func (a *Account) GetPrivateKey() crypto.PrivateKey

GetPrivateKey returns the account private key

func (*Account) GetRegistration

func (a *Account) GetRegistration() *registration.Resource

GetRegistration returns the ACME registration resource

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client manages ACME certificate lifecycle

func NewClient

func NewClient(cfg Config) (*Client, error)

NewClient creates a new ACME client

func (*Client) ObtainCertificate

func (c *Client) ObtainCertificate(_ context.Context) (*tls.Certificate, error)

ObtainCertificate requests a new certificate from ACME server

func (*Client) RenewCertificateIfNeeded

func (c *Client) RenewCertificateIfNeeded(_ context.Context) (*tls.Certificate, bool, error)

RenewCertificateIfNeeded checks expiry and renews if necessary

func (*Client) StartRenewalLoop

func (c *Client) StartRenewalLoop(ctx context.Context, checkInterval time.Duration,
	onRenewal func(*tls.Certificate)) error

StartRenewalLoop runs background renewal checks

type Config

type Config struct {
	DirectoryURL  string
	Email         string
	Domains       []string
	ChallengeType string
	RenewBefore   time.Duration
	StoragePath   string
	CABundle      string
}

Config holds ACME client configuration

func (*Config) Validate

func (c *Config) Validate() error

Validate checks if the ACME configuration is valid

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL