first draft CAA checking
Signed-off-by: Daniel Morsing <dmo@jetstack.io>
This commit is contained in:
parent
4db43bf04c
commit
bb853e5e79
@ -17,6 +17,7 @@ go_library(
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/acmechallenges/scheduler:go_default_library",
|
||||
"//pkg/issuer/acme/dns:go_default_library",
|
||||
"//pkg/issuer/acme/dns/util:go_default_library",
|
||||
"//pkg/issuer/acme/http:go_default_library",
|
||||
"//pkg/util:go_default_library",
|
||||
"//third_party/crypto/acme:go_default_library",
|
||||
|
||||
@ -31,6 +31,8 @@ import (
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
|
||||
controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
|
||||
acmeapi "github.com/jetstack/cert-manager/third_party/crypto/acme"
|
||||
|
||||
dnsutil "github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -131,6 +133,26 @@ func (c *Controller) Sync(ctx context.Context, ch *cmapi.Challenge) (err error)
|
||||
return nil
|
||||
}
|
||||
|
||||
// check for CAA records.
|
||||
// CAA records are static, so we don't have to present anything
|
||||
// before we check for them.
|
||||
|
||||
// Find out which identity the ACME server says it will use.
|
||||
dir, err := cl.Discover(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(dmo): figure out if missing CAA identity in directory
|
||||
// means no CAA check is performed by ACME server or if any valid
|
||||
// CAA would stop issuance (strongly suspect the former)
|
||||
if len(dir.CAA) != 0 {
|
||||
err := dnsutil.ValidateCAA(ch.Spec.DNSName, dir.CAA, ch.Spec.Wildcard)
|
||||
if err != nil {
|
||||
ch.Status.Reason = fmt.Sprintf("CAA self-check failed: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
solver, err := c.solverFor(ch.Spec.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -168,6 +168,58 @@ func dnsQuery(fqdn string, rtype uint16, nameservers []string, recursive bool) (
|
||||
return
|
||||
}
|
||||
|
||||
func ValidateCAA(domain string, issuerID []string, iswildcard bool) error {
|
||||
// see https://tools.ietf.org/html/rfc6844#section-4
|
||||
// for more information about how CAA lookup is performed
|
||||
fqdn := ToFqdn(domain)
|
||||
|
||||
issuerSet := make(map[string]bool)
|
||||
for _, s := range issuerID {
|
||||
issuerSet[s] = true
|
||||
}
|
||||
|
||||
//TODO(dmo): figure out if we need these servers to be configurable as well
|
||||
msg, err := dnsQuery(fqdn, dns.TypeCAA, RecursiveNameservers, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not validate CAA record: %s", err)
|
||||
}
|
||||
//TODO(dmo): follow CNAMES
|
||||
//TODO(dmo): look at labels above this one
|
||||
caas := make([]*dns.CAA, 0, len(msg.Answer))
|
||||
for _, rr := range msg.Answer {
|
||||
caa, ok := rr.(*dns.CAA)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
caas = append(caas, caa)
|
||||
}
|
||||
if len(caas) == 0 {
|
||||
// TODO(dmo): work up in the label
|
||||
return nil
|
||||
}
|
||||
if !matchCAA(caas, issuerSet, iswildcard) {
|
||||
// TODO(dmo): better error message
|
||||
return fmt.Errorf("CAA record does not match issuer")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func matchCAA(caas []*dns.CAA, issuerIDs map[string]bool, iswildcard bool) bool {
|
||||
expectedTag := "issue"
|
||||
if iswildcard {
|
||||
expectedTag = "issuewild"
|
||||
}
|
||||
for _, caa := range caas {
|
||||
if caa.Tag != expectedTag {
|
||||
continue
|
||||
}
|
||||
if issuerIDs[caa.Value] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// lookupNameservers returns the authoritative nameservers for the given fqdn.
|
||||
func lookupNameservers(fqdn string, nameservers []string) ([]string, error) {
|
||||
var authoritativeNss []string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user