github.com/outbrain/consul@v1.4.5/agent/connect/uri_signing.go (about) 1 package connect 2 3 import ( 4 "fmt" 5 "net/url" 6 "strings" 7 8 "github.com/hashicorp/consul/agent/structs" 9 ) 10 11 // SpiffeIDSigning is the structure to represent the SPIFFE ID for a 12 // signing certificate (not a leaf service). 13 type SpiffeIDSigning struct { 14 ClusterID string // Unique cluster ID 15 Domain string // The domain, usually "consul" 16 } 17 18 // URI returns the *url.URL for this SPIFFE ID. 19 func (id *SpiffeIDSigning) URI() *url.URL { 20 var result url.URL 21 result.Scheme = "spiffe" 22 result.Host = id.Host() 23 return &result 24 } 25 26 // Host is the canonical representation as a DNS-compatible hostname. 27 func (id *SpiffeIDSigning) Host() string { 28 return strings.ToLower(fmt.Sprintf("%s.%s", id.ClusterID, id.Domain)) 29 } 30 31 // CertURI impl. 32 func (id *SpiffeIDSigning) Authorize(ixn *structs.Intention) (bool, bool) { 33 // Never authorize as a client. 34 return false, true 35 } 36 37 // CanSign takes any CertURI and returns whether or not this signing entity is 38 // allowed to sign CSRs for that entity (i.e. represents the trust domain for 39 // that entity). 40 // 41 // I choose to make this a fixed centralized method here for now rather than a 42 // method on CertURI interface since we don't intend this to be extensible 43 // outside and it's easier to reason about the security properties when they are 44 // all in one place with "whitelist" semantics. 45 func (id *SpiffeIDSigning) CanSign(cu CertURI) bool { 46 switch other := cu.(type) { 47 case *SpiffeIDSigning: 48 // We can only sign other CA certificates for the same trust domain. Note 49 // that we could open this up later for example to support external 50 // federation of roots and cross-signing external roots that have different 51 // URI structure but it's simpler to start off restrictive. 52 return id.URI().String() == other.URI().String() 53 case *SpiffeIDService: 54 // The host component of the service must be an exact match for now under 55 // ascii case folding (since hostnames are case-insensitive). Later we might 56 // worry about Unicode domains if we start allowing customisation beyond the 57 // built-in cluster ids. 58 return strings.ToLower(other.Host) == id.Host() 59 default: 60 return false 61 } 62 } 63 64 // SpiffeIDSigningForCluster returns the SPIFFE signing identifier (trust 65 // domain) representation of the given CA config. If config is nil this function 66 // will panic. 67 // 68 // NOTE(banks): we intentionally fix the tld `.consul` for now rather than tie 69 // this to the `domain` config used for DNS because changing DNS domain can't 70 // break all certificate validation. That does mean that DNS prefix might not 71 // match the identity URIs and so the trust domain might not actually resolve 72 // which we would like but don't actually need. 73 func SpiffeIDSigningForCluster(config *structs.CAConfiguration) *SpiffeIDSigning { 74 return &SpiffeIDSigning{ClusterID: config.ClusterID, Domain: "consul"} 75 }