github.com/cilium/cilium@v1.16.2/pkg/auth/manager.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package auth 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/sirupsen/logrus" 11 12 "github.com/cilium/cilium/api/v1/models" 13 "github.com/cilium/cilium/pkg/auth/certs" 14 "github.com/cilium/cilium/pkg/datapath/types" 15 "github.com/cilium/cilium/pkg/identity" 16 "github.com/cilium/cilium/pkg/lock" 17 "github.com/cilium/cilium/pkg/maps/authmap" 18 "github.com/cilium/cilium/pkg/policy" 19 "github.com/cilium/cilium/pkg/time" 20 ) 21 22 // signalAuthKey used in the signalmap. Must reflect struct auth_key in the datapath 23 type signalAuthKey authmap.AuthKey 24 25 // low-cardinality stringer for metrics 26 func (key signalAuthKey) String() string { 27 return policy.AuthType(key.AuthType).String() 28 } 29 30 type AuthManager struct { 31 logger logrus.FieldLogger 32 nodeIDHandler types.NodeIDHandler 33 authHandlers map[policy.AuthType]authHandler 34 authmap authMapCacher 35 authSignalBackoffTime time.Duration 36 37 mutex lock.Mutex 38 pending map[authKey]struct{} 39 handleAuthenticationFunc func(a *AuthManager, k authKey, reAuth bool) 40 } 41 42 // authHandler is responsible to handle authentication for a specific auth type 43 type authHandler interface { 44 authenticate(*authRequest) (*authResponse, error) 45 authType() policy.AuthType 46 subscribeToRotatedIdentities() <-chan certs.CertificateRotationEvent 47 certProviderStatus() *models.Status 48 } 49 50 type authRequest struct { 51 localIdentity identity.NumericIdentity 52 remoteIdentity identity.NumericIdentity 53 remoteNodeIP string 54 } 55 56 type authResponse struct { 57 expirationTime time.Time 58 } 59 60 func newAuthManager(logger logrus.FieldLogger, authHandlers []authHandler, authmap authMapCacher, nodeIDHandler types.NodeIDHandler, authSignalBackoffTime time.Duration) (*AuthManager, error) { 61 ahs := map[policy.AuthType]authHandler{} 62 for _, ah := range authHandlers { 63 if ah == nil { 64 continue 65 } 66 if _, ok := ahs[ah.authType()]; ok { 67 return nil, fmt.Errorf("multiple handlers for auth type: %s", ah.authType()) 68 } 69 ahs[ah.authType()] = ah 70 } 71 72 return &AuthManager{ 73 logger: logger, 74 authHandlers: ahs, 75 authmap: authmap, 76 nodeIDHandler: nodeIDHandler, 77 pending: make(map[authKey]struct{}), 78 handleAuthenticationFunc: handleAuthentication, 79 authSignalBackoffTime: authSignalBackoffTime, 80 }, nil 81 } 82 83 // handleAuthRequest receives auth required signals and spawns a new go routine for each authentication request. 84 func (a *AuthManager) handleAuthRequest(_ context.Context, key signalAuthKey) error { 85 k := authKey{ 86 localIdentity: identity.NumericIdentity(key.LocalIdentity), 87 remoteIdentity: identity.NumericIdentity(key.RemoteIdentity), 88 remoteNodeID: key.RemoteNodeID, 89 authType: policy.AuthType(key.AuthType), 90 } 91 92 if k.localIdentity.IsReservedIdentity() || k.remoteIdentity.IsReservedIdentity() { 93 a.logger. 94 WithField("key", k). 95 Info("Reserved identity, skipping authentication as reserved identities are not compatible with authentication") 96 return nil 97 } 98 99 a.logger. 100 WithField("key", k). 101 Debug("Handle authentication request") 102 103 a.handleAuthenticationFunc(a, k, false) 104 105 return nil 106 } 107 108 func (a *AuthManager) handleCertificateRotationEvent(_ context.Context, event certs.CertificateRotationEvent) error { 109 a.logger. 110 WithField("identity", event.Identity). 111 Debug("Handle certificate rotation event") 112 113 all, err := a.authmap.All() 114 if err != nil { 115 return fmt.Errorf("failed to get all auth map entries: %w", err) 116 } 117 118 for k := range all { 119 if k.localIdentity == event.Identity || k.remoteIdentity == event.Identity { 120 if event.Deleted { 121 a.logger. 122 WithField("key", k). 123 Debug("Certificate delete event: deleting auth map entry") 124 if err := a.authmap.Delete(k); err != nil { 125 return fmt.Errorf("failed to delete auth map entry: %w", err) 126 } 127 } else { 128 a.handleAuthenticationFunc(a, k, true) 129 } 130 } 131 } 132 133 return nil 134 } 135 136 func handleAuthentication(a *AuthManager, k authKey, reAuth bool) { 137 if !a.markPendingAuth(k) { 138 a.logger. 139 WithField("key", k). 140 Debug("Pending authentication, skipping authentication") 141 return 142 } 143 144 go func(key authKey) { 145 defer a.clearPendingAuth(key) 146 147 if !reAuth { 148 // Check if the auth is actually required, as we might have 149 // updated the authmap since the datapath issued the auth 150 // required signal. 151 // If the entry was cached more than authSignalBackoffTime 152 // it will authenticate again, this is to make sure that 153 // we re-authenticate if the authmap was updated by an 154 // external source. 155 if i, err := a.authmap.GetCacheInfo(key); err == nil && i.expiration.After(time.Now()) && time.Now().Before(i.storedAt.Add(a.authSignalBackoffTime)) { 156 a.logger. 157 WithField("key", key). 158 WithField("storedAt", i.storedAt). 159 Debugf("Already authenticated in the past %s, skipping authentication", a.authSignalBackoffTime.String()) 160 return 161 } 162 } 163 164 if err := a.authenticate(key); err != nil { 165 a.logger. 166 WithError(err). 167 WithField("key", key). 168 Warning("Failed to authenticate request") 169 } 170 }(k) 171 } 172 173 // markPendingAuth checks if there is a pending authentication for the given key. 174 // If an auth is already pending returns false, otherwise marks the key as pending 175 // and returns true. 176 func (a *AuthManager) markPendingAuth(key authKey) bool { 177 a.mutex.Lock() 178 defer a.mutex.Unlock() 179 180 if _, exists := a.pending[key]; exists { 181 // Auth for this key is already pending 182 return false 183 } 184 a.pending[key] = struct{}{} 185 return true 186 } 187 188 // clearPendingAuth marks the pending authentication as finished. 189 func (a *AuthManager) clearPendingAuth(key authKey) { 190 a.logger. 191 WithField("key", key). 192 Debug("Clearing pending authentication") 193 194 a.mutex.Lock() 195 defer a.mutex.Unlock() 196 delete(a.pending, key) 197 } 198 199 func (a *AuthManager) authenticate(key authKey) error { 200 a.logger. 201 WithField("key", key). 202 Debug("Policy is requiring authentication") 203 204 // Authenticate according to the requested auth type 205 h, ok := a.authHandlers[key.authType] 206 if !ok { 207 return fmt.Errorf("unknown requested auth type: %s", key.authType) 208 } 209 210 nodeIP := a.nodeIDHandler.GetNodeIP(key.remoteNodeID) 211 if nodeIP == "" { 212 return fmt.Errorf("remote node IP not available for node ID %d", key.remoteNodeID) 213 } 214 215 authReq := &authRequest{ 216 localIdentity: key.localIdentity, 217 remoteIdentity: key.remoteIdentity, 218 remoteNodeIP: nodeIP, 219 } 220 221 authResp, err := h.authenticate(authReq) 222 if err != nil { 223 return fmt.Errorf("failed to authenticate with auth type %s: %w", key.authType, err) 224 } 225 226 if err = a.updateAuthMap(key, authResp.expirationTime); err != nil { 227 return fmt.Errorf("failed to update BPF map in datapath: %w", err) 228 } 229 230 a.logger. 231 WithField("key", key). 232 WithField("remote_node_ip", nodeIP). 233 Debug("Successfully authenticated") 234 235 return nil 236 } 237 238 func (a *AuthManager) updateAuthMap(key authKey, expirationTime time.Time) error { 239 val := authInfo{ 240 expiration: expirationTime, 241 } 242 243 if err := a.authmap.Update(key, val); err != nil { 244 return fmt.Errorf("failed to write auth information to BPF map: %w", err) 245 } 246 247 return nil 248 } 249 250 func (a *AuthManager) CertProviderStatus() *models.Status { 251 for _, h := range a.authHandlers { 252 status := h.certProviderStatus() 253 if status != nil { 254 // for now we only can have one cert provider 255 // once this changes we need to merge the statuses 256 return status 257 } 258 } 259 260 // if none was found auth is disabled 261 return &models.Status{ 262 State: models.StatusStateDisabled, 263 } 264 }