58 lines
1.9 KiB
Go
58 lines
1.9 KiB
Go
package tlsreload
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"proxy-pool/internal/domain/workerruntime"
|
|
)
|
|
|
|
var ErrInvalidSPIFFEIdentity = errors.New("invalid SPIFFE workload identity")
|
|
|
|
// ResolveSPIFFEIdentity returns the logical Worker or Checker ID encoded in a
|
|
// role-specific SPIFFE URI SAN. It only accepts the exact identity shape that
|
|
// the Controller authorizer accepts for a control-plane request.
|
|
func ResolveSPIFFEIdentity(certificateFile, keyFile, trustDomain, environment, role string) (string, error) {
|
|
if certificateFile == "" || keyFile == "" || trustDomain == "" || environment == "" || (role != "worker" && role != "checker") {
|
|
return "", ErrInvalidSPIFFEIdentity
|
|
}
|
|
certificate, err := tls.LoadX509KeyPair(certificateFile, keyFile)
|
|
if err != nil || len(certificate.Certificate) == 0 {
|
|
return "", fmt.Errorf("%w: load client certificate", ErrInvalidSPIFFEIdentity)
|
|
}
|
|
leaf, err := x509.ParseCertificate(certificate.Certificate[0])
|
|
if err != nil {
|
|
return "", fmt.Errorf("%w: parse client certificate", ErrInvalidSPIFFEIdentity)
|
|
}
|
|
var identity string
|
|
for _, uri := range leaf.URIs {
|
|
candidate, ok := spiffeIdentity(uri, trustDomain, environment, role)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if identity != "" {
|
|
return "", ErrInvalidSPIFFEIdentity
|
|
}
|
|
identity = candidate
|
|
}
|
|
if !workerruntime.ValidIdentifier(identity) {
|
|
return "", ErrInvalidSPIFFEIdentity
|
|
}
|
|
return identity, nil
|
|
}
|
|
|
|
func spiffeIdentity(uri *url.URL, trustDomain, environment, role string) (string, bool) {
|
|
if uri == nil || uri.Scheme != "spiffe" || uri.Host != trustDomain || uri.RawQuery != "" || uri.Fragment != "" {
|
|
return "", false
|
|
}
|
|
segments := strings.Split(strings.Trim(uri.Path, "/"), "/")
|
|
if len(segments) != 3 || segments[0] != environment || segments[1] != role || !workerruntime.ValidIdentifier(segments[2]) {
|
|
return "", false
|
|
}
|
|
return segments[2], true
|
|
}
|