testacme

package module
v0.0.0-...-e9f60da Latest Latest
Warning

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

Go to latest
Published: Feb 21, 2023 License: GPL-3.0 Imports: 27 Imported by: 0

README

testacme

testacme is a library enabling the use of ephemeral ACME integration & functional testing.

Usage

See test case here for an example ACME library obtaining a certificate using the tls-alpn-01 challenge.

Test authors can either use a shared instance or a test-scoped ACME instance:

func TestACMEFlow(t *testing.T) {
	pebble := testacme.NewPebble(testacme.NewTestingContext(t))

	user := testacme.ManagedUser(testacme.TestNamedEmail(t)).
		MustRegister(pebble)
	lego := testacme.LegoClient(pebble, user)
	cert, err := lego.Certificate.Obtain(certificate.ObtainRequest{
		Domains: []string{"some.fqdn.test."},
	})
	if err != nil {
		t.Fatalf("lego obtain: %v", err)
	}
	t.Logf("cert domain: %q", cert.Domain)

	// test continues to test renewal or something :)
}

Documentation

Overview

Package testacme provides a testing focused helper library which enables test authors to execute ACME integration and functional tests. The ACME server exercises challenge verifications with support for local-only environments by way of an included DNS resolver and convenience wrappers for Pebble.

https://github.com/letsencrypt/pebble

See package's test source files for example usages.

Index

Constants

View Source
const (
	// DefaultListPageSize is the default value used for Pebble.
	DefaultListPageSize = 3
	// DefautCertificateValidityPeriod is the default value used when issuing
	// certificates.
	DefautCertificateValidityPeriod = 5*365*24*time.Hour + 24*time.Hour // poor approximation of 5 years.
	// DefaultCertificateAlternateChains is the default number of Root CA chains generated.
	DefaultCertificateAlternateChains = 3
	// DefaultCertificateChainLength is the default number of certificates
	// generated in each Root CA chain.
	DefaultCertificateChainLength = 2 // root + intermediary
)
View Source
const (
	// TestTLD is a top level domain name suitable for testing contexts. This
	// symbol exists entirely for convenience.
	TestTLD = rfc6761.TestTLD
)

Variables

View Source
var GeneratedEmailDomain = "testacme." + TestTLD

Functions

func DNSRRMsg

func DNSRRMsg(rr dns.RR) *dns.Msg

DNSRRMsg expands the given dns.RR record into a dns.Msg with its implied Question and embeds the RR in the Answers.

func LegoAPIClient

func LegoAPIClient(testacme TestACME, user registration.User) *acmeapi.Core

func LegoClient

func LegoClient(testacme TestACME, user registration.User) *lego.Client

func ManagedUser

func ManagedUser(email string) *managedUser

func MustRR

func MustRR(rr string) dns.RR

MustRR is a helper to create RR values from opaque strings. Panics on invalid input. This is intended for use in tests where stable known values are used for construction.

func NewTestingContext

func NewTestingContext(t testing.TB) context.Context

NewTestingContext creates a context that's canceled at the end of the current test scope.

func TestNamedEmail

func TestNamedEmail(t testing.TB) string

Types

type DNS

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

DNS is a nameserver offering only limited capabilities. The server is intended for use in testacme where most (or all) queries are expected to resolve to the local host. The backing NameserverDB is the "authority" and can

func NewDNS

func NewDNS(ctx context.Context, dnsdb *NameserverDB) (*DNS, error)

NewDNS creates an ephemeral nameserver to drive testacme verifications. Queries will default to 127.0.0.1 unless otherwise configured in the supporting NameserverDB.

func SharedDNS

func SharedDNS() *DNS

SharedDNS provides a shared instance of the helper DNS server, suitable for concurrent use.

func (DNS) Addr

func (d DNS) Addr() net.Addr

Addr returns the net.Addr where the nameserver is listening.

type NameserverDB

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

NameserverDB holds a basic datastore of query questions mapped to query responses. This can be used directly as a DNS handler - and is by DNS above.

func SharedNameserverDB

func SharedNameserverDB() *NameserverDB

SharedNameserverDB provides a shared instance of the NameserverDB used to respond to DNS queries. This instance is used when calling SharedDNS - callers may add additional responses using the provided methods.

func (*NameserverDB) DefaultA

func (db *NameserverDB) DefaultA(r *dns.Msg) *dns.Msg

DefaultA is the message prototype for a default response.

func (*NameserverDB) LookupReply

func (db *NameserverDB) LookupReply(r *dns.Msg) *dns.Msg

LookupReply retrieves a DNS query response.

func (*NameserverDB) RemoveReplyTo

func (db *NameserverDB) RemoveReplyTo(r dns.Msg)

RemoveReplyTo immediately removes the given DNS message (by its question) and will no longer be returned in DNS query responses.

func (*NameserverDB) ServeDNS

func (db *NameserverDB) ServeDNS(w dns.ResponseWriter, r *dns.Msg)

ServeDNS provides the DNS replies for local ACME validation.

func (*NameserverDB) StoreExact

func (db *NameserverDB) StoreExact(r dns.Msg)

StoreExact stores the given DNS message for lookup when resolving names.

type Pebble

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

Pebble is a testacme implementation suitable for use in concurrent testing (depending on verification)

func NewPebble

func NewPebble(ctx context.Context, options ...PebbleOption) Pebble

NewPebble creates an initialized, un-started, Pebble testacme server. The services are automatically shutdown with respect to the given context. Also see `SharedPebble()`.

func SharedPebble

func SharedPebble() Pebble

SharedPebble provides a shared instance of the Pebble ACME server, suitable for concurrent use. Note that some test cases & implementations may want (and should!) create a new instance for each test. However, the SharedPebble instance should be preferred to reduce the computational load on the system during tests as cryptographic materials are generated on the fly.

func (Pebble) ACMEDirectoryURL

func (p Pebble) ACMEDirectoryURL() string

ACMEDirectoryURL returns the URL to the testacme's ACME directory API endpoint. Pebble does not and will not serve its Directory at `/directory` as LetsEncrypt does to encourage design & testing of Directory lookup based usage.

https://github.com/letsencrypt/pebble/blob/d5fa73840ef4a2efa7870648ae174627ef001e9c/wfe/wfe.go#L39-L42

func (Pebble) Client

func (p Pebble) Client() *http.Client

Client provides a configured HTTP Client suitable for dialing the testacme ACME services. See tests for example of connections made using the returned http.Client.

func (Pebble) HTTPVerificationPort

func (p Pebble) HTTPVerificationPort() int

HTTPVerificationPort is the port that this testacme server will connect to for HTTP verification challenges.

func (Pebble) ManagementServer

func (p Pebble) ManagementServer() *httptest.Server

ManagementServer provides the testacme (Pebble) management server to be used in tests. The server is started before returned, if not already started.

func (Pebble) Server

func (p Pebble) Server() *httptest.Server

Server provides the testacme (Pebble) server to be used ibn tests. The server is started before returned, if not already started.

func (Pebble) Shutdown

func (p Pebble) Shutdown()

Shutdown will stop all Pebble servers. This does *not* block on shutdown and instead immediately returns control to callers.

func (Pebble) Start

func (p Pebble) Start()

Start will startup all Pebble servers on their listeners.

func (Pebble) TLSVerificationPort

func (p Pebble) TLSVerificationPort() int

TLSVerificationPort is the port that this testacme server will connect to for TLS verification challenges.

type PebbleOption

type PebbleOption = func(*pebbleConfig) error

PebbleOption are functions that tune configuration of the Pebble services.

func WithPebbleDNS

func WithPebbleDNS(dns *DNS) PebbleOption

WithPebbleDNS uses the provided DNS implementation when querying for verification and connection addresses.

func WithPebbleHTTPVerificationPort

func WithPebbleHTTPVerificationPort(port uint16) PebbleOption

WithPebbleHTTPVerificationPort uses the provided port number in HTTP challenge verifications.

func WithPebbleLogger

func WithPebbleLogger(logger *log.Logger) PebbleOption

WithPebbleLogger uses the provided logger in Pebble services to log debug and informational messages at runtime.

func WithPebbleTLSVerificationPort

func WithPebbleTLSVerificationPort(port uint16) PebbleOption

WithPebbleTLSVerificationPort uses the provided port number in TLS challenge verifications.

type PebbleServerConfig

type PebbleServerConfig struct {
	// ListPageSize is the number used to split pages when pagingating response.
	ListPageSize int `json:"per-page"`
	// HTTPVerificationPort is the port connected to for HTTP based challenge
	// verification.
	HTTPVerificationPort int `json:"http-verification-port"`
	// TLSVerificationPort is the port connected to for TLS based challenge
	// verification.
	TLSVerificationPort int `json:"tls-verification-port"`
	// VerificationDNSResolver is the DNS resolver to use when performing
	// verification.
	VerificationDNSResolver string `json:"verification-dns-resolver"`
	// PermitInsecureGET permits HTTP GET requests to API endpoints. This mimics
	// LetsEncrypt's behavior however the spec is for POST - which is the
	// default when this is left unset or set to false.
	PermitInsecureGET bool `json:"permit-insecure-get"`
	// RequireExternalAccountBinding requires EAB values provided in API
	// requests. This is not fully plumbed - if you find that it works (or that
	// it doesn't) , please create an issue to improve the implementation.
	RequireExternalAccountBinding bool `json:"require-external-account-binding"`
	// CertificateValidityPeriod is the duration for which vended certificates
	// are valid for.
	CertificateValidityPeriod time.Duration `json:"certificate-validity-period"`
	// CertificateAlternateChains is the number of alternate Root CA chains to
	// build and operate the testacme CA (Pebble) with.
	CertificateAlternateChains int `json:"certificate-alternate-chains"`
	// CertificateChainLength is the total number of certificates in the
	// generated Root CA chains. Setting this to `1` generates *only* Root CA
	// certificate(s) while `2` would include a single Intermediate CA.
	CertificateChainLength int `json:"certificate-chain-length"`
}

PebbleServerConfig provides configuration used to stand up the Pebble testacme instance. Note that callers *can* make an inconsistent setup by explicitly building up their CA, VA, and DB values.. so take care when being creative.

type Porter

type Porter interface {
	// HTTPVerificationPort is the port number used in HTTP challenge
	// verification.
	HTTPVerificationPort() int
	// TLSVerificationPort is the port number used in TLS challenge
	// verification.
	TLSVerificationPort() int
}

Porter describes the methods provided to lookup the ports used in verification.

type TestACME

type TestACME interface {
	Porter
	// Client provides a configured HTTP client (eg: with TLS configured).
	Client() *http.Client
	// Server returns the running ACME HTTP server.
	Server() *httptest.Server
	// ACMEDirectoryURL is the URL to fetch RFC8555 7.1.1 compliant Directory
	// object for this ACME instance.
	//
	// https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.1
	ACMEDirectoryURL() string
}

TestACME describes a minimal ACME testacme implementation suitable for integration & functional testing usages.

Directories

Path Synopsis
pkg
randomports
Package randomports provides helpers to get random, free port numbers for testing listener use cases.
Package randomports provides helpers to get random, free port numbers for testing listener use cases.
rfc6761
Package rfc6761 provides helpers for a subset of rfc6761 domain TLD.
Package rfc6761 provides helpers for a subset of rfc6761 domain TLD.

Jump to

Keyboard shortcuts

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