Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service Mesh mTLS: DelegatedIdentity SPIFFE API #23968

Merged
merged 3 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ require (
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.15.0
github.com/spiffe/spire-api-sdk v1.5.5
github.com/stretchr/testify v1.8.2
github.com/tidwall/gjson v1.14.4
github.com/tidwall/sjson v1.2.5
Expand Down
6 changes: 6 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions pkg/auth/certs/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package certs

import (
"crypto/tls"
"crypto/x509"
)

type CertificateProvider interface {
// GetTrustBundle gives the CA trust bundle for the certificate provider
// this is then used to verify the certificates given by the peer in the handshake
GetTrustBundle() (*x509.CertPool, error)

// GetCertificateForIdentity gives the certificate and intermediates required
// to send as trust chain for a certain identity as well as a private key
GetCertificateForIdentity(identity string) (*tls.Certificate, error)

// ValidateIdentity will check if the SANs or other identity methods are valid
// for the given Cilium identity this function is needed as SPIFFE encodes the
// full ID in the URI SAN.
ValidateIdentity(identity string, cert *x509.Certificate) (bool, error)
}
74 changes: 74 additions & 0 deletions pkg/auth/spire/certificate_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package spire

import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
)

// This file implements the CertificateProvider interface

func (s *SpireDelegateClient) GetTrustBundle() (*x509.CertPool, error) {
if s.trustBundle == nil {
return nil, errors.New("trust bundle not yet available")
}
return s.trustBundle, nil
}

func (s *SpireDelegateClient) GetCertificateForIdentity(identity string) (*tls.Certificate, error) {
spiffeID := s.sniToSPIFFEID(identity)
svid, ok := s.svidStore[spiffeID]
if !ok {
return nil, fmt.Errorf("no SPIFFE ID for %s", spiffeID)
}

if len(svid.X509Svid.CertChain) == 0 {
return nil, fmt.Errorf("no certificate chain inside %s", spiffeID)
}

var leafCert *x509.Certificate
for _, cert := range svid.X509Svid.CertChain {
cert, err := x509.ParseCertificate(cert)
if err != nil {
return nil, fmt.Errorf("failed to parse certificate: %w", err)
}

if !cert.IsCA {
leafCert = cert
break
}
}
if leafCert == nil {
return nil, fmt.Errorf("no leaf certificate inside %s", spiffeID)
}

privKey, err := x509.ParsePKCS8PrivateKey(svid.X509SvidKey)
if err != nil {
return nil, fmt.Errorf("failed to parse private keyof %s: %w", spiffeID, err)
}

return &tls.Certificate{
Certificate: svid.X509Svid.CertChain,
PrivateKey: privKey,
Leaf: leafCert,
}, nil
}

func (s *SpireDelegateClient) sniToSPIFFEID(sni string) string {
return fmt.Sprintf("spiffe://%s/cilium-id/%s", s.cfg.SpiffeTrustDomain, sni)
}

func (s *SpireDelegateClient) ValidateIdentity(identity string, cert *x509.Certificate) (bool, error) {
spiffeID := s.sniToSPIFFEID(identity)

// Spec: SVIDs containing more than one URI SAN MUST be rejected
if len(cert.URIs) != 1 {
return false, errors.New("SPIFFE IDs must have exactly one URI SAN")
}

return cert.URIs[0].String() == spiffeID, nil
}