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  }