Documentation
¶
Overview ¶
Package certflow decides whether a domain is ready for a public certificate, tells operators the truth about the certificate it has, and retries stuck renewals with backoff. It holds no ACME client: issuance and renewal stay with the embedded ingress.
Index ¶
- Constants
- func DaysLeft(notAfter, now time.Time) int
- func FailDays() int
- func IsRateLimitError(msg string) bool
- type Badge
- type Candidate
- type Existing
- type Input
- type Item
- type ItemState
- type Kind
- type Ledger
- type Limits
- type RateLimit
- type Renewal
- type RenewalResult
- type ReplaceError
- type Result
- type RetryState
- type Snapshot
- type Watchdog
- type WatchdogDeps
Constants ¶
const ( EnvFailedPerHour = "APP_ACME_FAILED_PER_HOUR" EnvDuplicatePerWeek = "APP_ACME_DUPLICATE_PER_WEEK" )
Env names for the Let's Encrypt limits the ledger reasons about.
const ( ReasonFailedValidations = "failed_validations" ReasonDuplicates = "duplicate_certificates" ReasonCARateLimited = "ca_rate_limited" )
Rate limit reasons.
const ( CodeIssuable = "issuable" CodeUpstream = "upstream_proxy" CodeDNS = "dns" CodePorts = "ports" CodeCAA = "caa" CodeEmail = "email" CodeRateLimit = "rate_limit" CodeStaging = "staging" )
Preflight item codes.
const ( EnvWatchdogInterval = "APP_CERT_WATCHDOG_INTERVAL" EnvWatchdogBackoff = "APP_CERT_WATCHDOG_BACKOFF" )
Env names for the renewal watchdog.
const CodeReplaces = "replaces_certificate"
CodeReplaces is the preflight item and API error code for a staging request that would replace a working certificate.
const (
EnvFailDays = "APP_CERT_FAIL_DAYS"
)
Env names and defaults for the thresholds this package reads.
Variables ¶
This section is empty.
Functions ¶
func FailDays ¶
func FailDays() int
FailDays is how close to expiry an automatically renewed certificate turns the doctor red, from APP_CERT_FAIL_DAYS (default 14).
func IsRateLimitError ¶
IsRateLimitError reports whether a CA error text is a rate limit answer.
Types ¶
type Badge ¶
type Badge struct {
Kind Kind `json:"kind"`
DaysLeft int `json:"days_left"`
LastRenewal *Renewal `json:"last_renewal,omitempty"`
// NextRetryAt is when the watchdog tries again, set only while a renewal
// is stuck or failing.
NextRetryAt *time.Time `json:"next_retry_at,omitempty"`
}
Badge is the per-domain certificate truth shown on lists and the overview.
type Candidate ¶
type Candidate struct {
Domain string
Reason string
// Expired certificates are cleared before re-issuing; valid ones are left in place.
Expired bool
// Blocked is set while a CA rate limit makes a try pointless.
Blocked bool
}
Candidate is a certificate whose renewal failed or is stuck.
type Input ¶
type Input struct {
Domain string
Email string
DefaultEmail string
Staging bool
TLSUpstream bool
Report domaindoctor.Report
Existing []Existing
History Snapshot
Limits Limits
LastCAError string
LastCAErrorTime time.Time
Now time.Time
}
Input is everything Evaluate decides from. The caller fills Report from the domain doctor with ACME forced on, so CAA and port checks really run.
type Item ¶
type Item struct {
Code string `json:"code"`
State ItemState `json:"state"`
Detail string `json:"detail"`
Fix string `json:"fix,omitempty"`
}
Item is one preflight finding with the next step in plain words.
type Kind ¶
type Kind string
Kind says who signed the certificate a domain serves.
const ( KindNone Kind = "none" KindInternal Kind = "internal" KindStaging Kind = "staging" KindLetsEncrypt Kind = "letsencrypt" KindCustom Kind = "custom" KindProxy Kind = "proxy" KindOther Kind = "other" )
Kind values, from least to most trusted by browsers.
func Classify ¶
Classify names the signer from the leaf's issuer common name, the row's source and who owns TLS for the host.
func (Kind) AutoRenewed ¶
AutoRenewed reports whether the platform renews this kind itself.
type Ledger ¶
type Ledger struct {
// contains filtered or unexported fields
}
Ledger remembers recent production attempts per hostname so the next safe time can be shown before another try burns a limit. It lives in memory: a restart forgets it, and the CA's own answer still wins.
func (*Ledger) MarkStarted ¶
MarkStarted notes when a guided issuance began for domain.
func (*Ledger) RecordFailure ¶
RecordFailure notes a failed production validation; repeats of one timestamp are ignored.
func (*Ledger) RecordIssued ¶
RecordIssued notes a production certificate issued for domain.
type Limits ¶
Limits are the CA limits that matter for one hostname.
func LimitsFromEnv ¶
func LimitsFromEnv() Limits
LimitsFromEnv reads the limits, defaulting to Let's Encrypt's published ones.
type RateLimit ¶
type RateLimit struct {
Blocked bool
// NextSafeAt is the earliest time another production try is safe.
NextSafeAt time.Time
// Reason is "failed_validations", "duplicate_certificates" or "ca_rate_limited".
Reason string
}
RateLimit is the verdict on trying again now.
type Renewal ¶
type Renewal struct {
At time.Time `json:"at"`
Result RenewalResult `json:"result"`
Error string `json:"error,omitempty"`
}
Renewal is the last issue or renewal attempt as an operator reads it.
type RenewalResult ¶
type RenewalResult string
RenewalResult is the outcome of the last automatic issue or renewal.
const ( RenewalOK RenewalResult = "ok" RenewalFailed RenewalResult = "failed" )
RenewalResult values.
type ReplaceError ¶
ReplaceError says a staging request would swap a working certificate for an untrusted one.
func StagingConflict ¶
func StagingConflict(domain string, existing []Existing) *ReplaceError
StagingConflict returns the first working certificate a staging request would put at risk, or nil. Switching the CA drops every stored ACME certificate server-wide, so a working Let's Encrypt or public CA certificate on any domain counts; an uploaded or proxy certificate counts only for the requested domain.
func (*ReplaceError) Error ¶
func (e *ReplaceError) Error() string
Error is the plain-language message shown by the API, CLI and dashboard.
type Result ¶
type Result struct {
Domain string `json:"domain"`
Staging bool `json:"staging"`
// Email is the contact that will be used: the typed one or the inferred default.
Email string `json:"email"`
// Ready is true when no item failed.
Ready bool `json:"ready"`
Items []Item `json:"items"`
// NextSafeAt is set when a rate limit is in the way.
NextSafeAt *time.Time `json:"next_safe_at,omitempty"`
}
Result is the whole preflight for one domain.
type RetryState ¶
RetryState is one stuck domain's retry bookkeeping.
type Snapshot ¶
Snapshot is the recent history of one hostname.
func (Snapshot) Check ¶
func (s Snapshot) Check(lim Limits, now time.Time, lastCAErr string, lastCAErrAt time.Time) RateLimit
Check decides whether a production attempt is safe at now. lastCAErr is the CA's latest error text and lastCAErrAt its time, so a "rate limited" answer pauses even when this process never counted the attempts.
type Watchdog ¶
type Watchdog struct {
// contains filtered or unexported fields
}
Watchdog retries stuck renewals with exponential backoff per domain.
func NewWatchdog ¶
func NewWatchdog(deps WatchdogDeps) *Watchdog
NewWatchdog builds a watchdog, reading its timings from the environment.