Skip to content

Commit

Permalink
Add SubscribeToRotatedIdentities interface
Browse files Browse the repository at this point in the history
This change adds a SubscribeToRotatedIdentities function.
This gives a channel which is used to pass identity updates
back from the certificate proider to the auth manager.
In the auth manager there can better be acted upon to
receive the IDs and re-trigger a mTLS handshake if needed.

Signed-off-by: Maartje Eyskens <maartje.eyskens@isovalent.com>
  • Loading branch information
meyskens authored and ti-mo committed Apr 25, 2023
1 parent a8e4873 commit d42f4af
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 50 deletions.
1 change: 1 addition & 0 deletions Documentation/cmdref/cilium-agent.md

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

47 changes: 24 additions & 23 deletions Documentation/cmdref/cilium-agent_hive.md

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

45 changes: 23 additions & 22 deletions Documentation/cmdref/cilium-agent_hive_dot-graph.md

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

5 changes: 5 additions & 0 deletions pkg/auth/always_fail_authhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package auth
import (
"errors"

"github.com/cilium/cilium/pkg/auth/certs"
"github.com/cilium/cilium/pkg/policy"
)

Expand All @@ -26,3 +27,7 @@ func (r *alwaysFailAuthHandler) authenticate(authReq *authRequest) (*authRespons
func (r *alwaysFailAuthHandler) authType() policy.AuthType {
return policy.AuthTypeAlwaysFail
}

func (r *alwaysFailAuthHandler) subscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent {
return nil
}
7 changes: 7 additions & 0 deletions pkg/auth/certs/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
"github.com/cilium/cilium/pkg/identity"
)

type CertificateRotationEvent struct {
Identity identity.NumericIdentity
}

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
Expand All @@ -29,4 +33,7 @@ type CertificateProvider interface {

// SNIToNumericIdentity will return the Cilium Identity for a given SNI
SNIToNumericIdentity(sni string) (identity.NumericIdentity, error)

// SubscribeToRotatedIdentities will return a channel with the identities that have rotated certificates
SubscribeToRotatedIdentities() <-chan CertificateRotationEvent
}
2 changes: 2 additions & 0 deletions pkg/auth/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net"
"time"

"github.com/cilium/cilium/pkg/auth/certs"
"github.com/cilium/cilium/pkg/identity"
"github.com/cilium/cilium/pkg/ip"
"github.com/cilium/cilium/pkg/monitor"
Expand All @@ -30,6 +31,7 @@ type ipCache interface {
type authHandler interface {
authenticate(*authRequest) (*authResponse, error)
authType() policy.AuthType
subscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent
}

type authRequest struct {
Expand Down
5 changes: 5 additions & 0 deletions pkg/auth/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"

"github.com/cilium/cilium/api/v1/flow"
"github.com/cilium/cilium/pkg/auth/certs"
"github.com/cilium/cilium/pkg/monitor"
monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
"github.com/cilium/cilium/pkg/policy"
Expand Down Expand Up @@ -163,6 +164,10 @@ func (r *fakeAuthHandler) authType() policy.AuthType {
return policy.AuthType(255)
}

func (r *fakeAuthHandler) subscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent {
return nil
}

// Fake DatapathAuthenticator
type fakeDatapathAuthenticator struct {
authenticated bool
Expand Down
4 changes: 4 additions & 0 deletions pkg/auth/mtls_authhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,7 @@ func (m *mtlsAuthHandler) verifyPeerCertificate(id *identity.NumericIdentity, ca

return expirationTime, nil
}

func (m *mtlsAuthHandler) subscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent {
return m.cert.SubscribeToRotatedIdentities()
}
5 changes: 5 additions & 0 deletions pkg/auth/mtls_authhandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"testing"
"time"

"github.com/cilium/cilium/pkg/auth/certs"
"github.com/cilium/cilium/pkg/identity"
)

Expand Down Expand Up @@ -79,6 +80,10 @@ func (f *fakeCertificateProvider) SNIToNumericIdentity(sni string) (identity.Num
return identity.ParseNumericIdentity(idStr)
}

func (f *fakeCertificateProvider) SubscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent {
return nil
}

func generateTestCertificates(t *testing.T) (map[string]*x509.Certificate, map[string]*ecdsa.PrivateKey, *x509.CertPool) {
caPool := x509.NewCertPool()

Expand Down
5 changes: 5 additions & 0 deletions pkg/auth/null_authhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package auth
import (
"time"

"github.com/cilium/cilium/pkg/auth/certs"
"github.com/cilium/cilium/pkg/policy"
)

Expand All @@ -25,3 +26,7 @@ func (r *nullAuthHandler) authenticate(authReq *authRequest) (*authResponse, err
func (r *nullAuthHandler) authType() policy.AuthType {
return policy.AuthTypeNull
}

func (r *nullAuthHandler) subscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent {
return nil
}
15 changes: 15 additions & 0 deletions pkg/auth/spire/certificate_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"fmt"
"strings"

"github.com/cilium/cilium/pkg/auth/certs"
"github.com/cilium/cilium/pkg/identity"
)

Expand Down Expand Up @@ -67,6 +68,16 @@ func (s *SpireDelegateClient) sniToSPIFFEID(id identity.NumericIdentity) string
return "spiffe://" + s.cfg.SpiffeTrustDomain + "/identity/" + id.String()
}

func (s *SpireDelegateClient) spiffeIDToNumericIdentity(spiffeID string) (identity.NumericIdentity, error) {
prefix := "spiffe://" + s.cfg.SpiffeTrustDomain + "/identity/"
if !strings.HasPrefix(spiffeID, prefix) {
return 0, fmt.Errorf("SPIFFE ID %s does not belong to our trust domain or is not in the valid format", spiffeID)
}

idStr := strings.TrimPrefix(spiffeID, prefix)
return identity.ParseNumericIdentity(idStr)
}

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

Expand All @@ -91,3 +102,7 @@ func (s *SpireDelegateClient) SNIToNumericIdentity(sni string) (identity.Numeric
idStr := strings.TrimSuffix(sni, suffix)
return identity.ParseNumericIdentity(idStr)
}

func (s *SpireDelegateClient) SubscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent {
return s.rotatedIdentitiesChan
}
92 changes: 92 additions & 0 deletions pkg/auth/spire/certificate_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
delegatedidentityv1 "github.com/spiffe/spire-api-sdk/proto/spire/api/agent/delegatedidentity/v1"
"github.com/spiffe/spire-api-sdk/proto/spire/api/types"

"github.com/cilium/cilium/pkg/auth/certs"
"github.com/cilium/cilium/pkg/identity"
"github.com/cilium/cilium/pkg/logging"
"github.com/cilium/cilium/pkg/logging/logfields"
Expand Down Expand Up @@ -396,3 +397,94 @@ func TestSpireDelegateClient_GetCertificateForIdentity(t *testing.T) {
})
}
}

func TestSpireDelegateClient_SubscribeToRotatedIdentities(t *testing.T) {
tests := []struct {
name string
actions []func(t *testing.T, s *SpireDelegateClient)
events []certs.CertificateRotationEvent
}{
{
name: "receive no event on a new ID",
actions: []func(t *testing.T, s *SpireDelegateClient){
func(t *testing.T, s *SpireDelegateClient) {
s.handleX509SVIDUpdate([]*delegatedidentityv1.X509SVIDWithKey{
{
X509Svid: &types.X509SVID{
Id: &types.SPIFFEID{
TrustDomain: "test.cilium.io",
Path: "/identity/1234",
},
ExpiresAt: time.Now().Add(time.Hour).Unix(),
},
},
})
},
},
events: []certs.CertificateRotationEvent{},
},
{
name: "receive 1 updated event",
actions: []func(t *testing.T, s *SpireDelegateClient){
func(t *testing.T, s *SpireDelegateClient) {
s.handleX509SVIDUpdate([]*delegatedidentityv1.X509SVIDWithKey{
{
X509Svid: &types.X509SVID{
Id: &types.SPIFFEID{
TrustDomain: "test.cilium.io",
Path: "/identity/1234",
},
ExpiresAt: time.Now().Add(time.Hour).Unix(),
},
},
})
},
func(t *testing.T, s *SpireDelegateClient) {
// Update the certificate
s.handleX509SVIDUpdate([]*delegatedidentityv1.X509SVIDWithKey{
{
X509Svid: &types.X509SVID{
Id: &types.SPIFFEID{
TrustDomain: "test.cilium.io",
Path: "/identity/1234",
},
ExpiresAt: time.Now().Add(2 * time.Hour).Unix(),
},
},
})
},
},
events: []certs.CertificateRotationEvent{
{
Identity: 1234,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &SpireDelegateClient{
cfg: SpireDelegateConfig{
SpiffeTrustDomain: "test.cilium.io",
},
log: log,
rotatedIdentitiesChan: make(chan certs.CertificateRotationEvent, 10),
svidStore: make(map[string]*delegatedidentityv1.X509SVIDWithKey),
}
for _, action := range tt.actions {
action(t, s)
}
got := []certs.CertificateRotationEvent{}
select {
case event := <-s.SubscribeToRotatedIdentities():
got = append(got, event)
default:
break
}

if !reflect.DeepEqual(got, tt.events) {
t.Errorf("SpireDelegateClient.SubscribeToRotatedIdentities() = %v, want %v", got, tt.events)
}
})
}
}

0 comments on commit d42f4af

Please sign in to comment.