1 package identity
2
3 import (
4 "context"
5 "crypto/sha256"
6 "crypto/x509"
7 "encoding/hex"
8 "errors"
9 "fmt"
10 "strings"
11 "sync"
12 "time"
13
14 v1 "k8s.io/api/core/v1"
15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16 "k8s.io/apimachinery/pkg/runtime"
17
18 pb "github.com/linkerd/linkerd2-proxy-api/go/identity"
19 "github.com/linkerd/linkerd2/pkg/tls"
20 log "github.com/sirupsen/logrus"
21 "google.golang.org/grpc"
22 "google.golang.org/grpc/codes"
23 "google.golang.org/grpc/status"
24 "google.golang.org/protobuf/types/known/timestamppb"
25 )
26
27 const (
28
29
30 DefaultIssuanceLifetime = 24 * time.Hour
31
32
33
34 EnvTrustAnchors = "LINKERD2_PROXY_IDENTITY_TRUST_ANCHORS"
35 eventTypeSkipped = "IssuerUpdateSkipped"
36 eventTypeUpdated = "IssuerUpdated"
37 eventTypeFailed = "IssuerValidationFailed"
38 eventTypeIssuedLeafCert = "IssuedLeafCertificate"
39 )
40
41 type (
42
43 Service struct {
44 pb.UnimplementedIdentityServer
45 validator Validator
46 trustAnchors *x509.CertPool
47 issuer *tls.Issuer
48 issuerMutex *sync.RWMutex
49 validity *tls.Validity
50 recordEvent func(parent runtime.Object, eventType, reason, message string)
51
52 expectedName, issuerPathCrt, issuerPathKey string
53 }
54
55
56
57 Validator interface {
58
59
60
61
62
63
64
65
66 Validate(context.Context, []byte) (string, error)
67 }
68
69
70
71 InvalidToken struct{ Reason string }
72
73
74
75 NotAuthenticated struct{}
76 )
77
78
79 func (svc *Service) Initialize() error {
80 credentials, err := svc.loadCredentials()
81 if err != nil {
82 return err
83 }
84 svc.updateIssuer(credentials)
85 return nil
86 }
87
88 func (svc *Service) updateIssuer(newIssuer tls.Issuer) {
89 svc.issuerMutex.Lock()
90 svc.issuer = &newIssuer
91 log.Debug("Issuer has been updated")
92 svc.issuerMutex.Unlock()
93 }
94
95
96 func (svc *Service) Run(issuerEvent <-chan struct{}, issuerError <-chan error) {
97 for {
98 select {
99 case <-issuerEvent:
100 if err := svc.Initialize(); err != nil {
101 message := fmt.Sprintf("Skipping issuer update as certs could not be read from disk: %s", err)
102 log.Warn(message)
103 svc.recordEvent(nil, v1.EventTypeWarning, eventTypeSkipped, message)
104 } else {
105 message := "Updated identity issuer"
106 log.Infof(message)
107 svc.recordEvent(nil, v1.EventTypeNormal, eventTypeUpdated, message)
108 }
109 case err := <-issuerError:
110 log.Warnf("Received error from fs watcher: %s", err)
111 }
112 }
113 }
114
115 func (svc *Service) loadCredentials() (tls.Issuer, error) {
116 creds, err := tls.ReadPEMCreds(
117 svc.issuerPathKey,
118 svc.issuerPathCrt,
119 )
120
121 if err != nil {
122 return nil, fmt.Errorf("failed to read CA from disk: %w", err)
123 }
124
125
126 if err := creds.Crt.Verify(svc.trustAnchors, "", time.Time{}); err != nil {
127 return nil, fmt.Errorf("failed to verify issuer credentials for '%s' with trust anchors: %w", svc.expectedName, err)
128 }
129
130 if !creds.Certificate.IsCA {
131 return nil, fmt.Errorf("failed to verify issuer certificate: it must be an intermediate-CA, but it is not")
132 }
133
134 log.Debugf("Loaded issuer cert: %s", creds.EncodeCertificatePEM())
135 return tls.NewCA(*creds, *svc.validity), nil
136 }
137
138
139 func NewService(validator Validator, trustAnchors *x509.CertPool, validity *tls.Validity, recordEvent func(parent runtime.Object, eventType, reason, message string), expectedName, issuerPathCrt, issuerPathKey string) *Service {
140 return &Service{
141 pb.UnimplementedIdentityServer{},
142 validator,
143 trustAnchors,
144 nil,
145 &sync.RWMutex{},
146 validity,
147 recordEvent,
148 expectedName,
149 issuerPathCrt,
150 issuerPathKey,
151 }
152 }
153
154
155
156 func Register(g *grpc.Server, s *Service) {
157 pb.RegisterIdentityServer(g, s)
158 }
159
160
161
162 func (svc *Service) ensureIssuerStillValid() error {
163 issuer := *svc.issuer
164 switch is := issuer.(type) {
165 case *tls.CA:
166
167 return is.Cred.Verify(svc.trustAnchors, "", time.Time{})
168 default:
169 return fmt.Errorf("unsupported issuer type. Expected *tls.CA, got %v", is)
170 }
171 }
172
173
174 func (svc *Service) Certify(ctx context.Context, req *pb.CertifyRequest) (*pb.CertifyResponse, error) {
175 svc.issuerMutex.RLock()
176 defer svc.issuerMutex.RUnlock()
177
178 if svc.issuer == nil {
179 log.Warn("Certificate issuer is not ready")
180 return nil, status.Error(codes.Unavailable, "cert issuer not ready yet")
181 }
182
183
184 reqIdentity, tok, csr, err := checkRequest(req)
185 if err != nil {
186 return nil, status.Error(codes.InvalidArgument, err.Error())
187 }
188
189 if err := svc.ensureIssuerStillValid(); err != nil {
190 log.Errorf("could not process CSR because of CA cert validation failure: %s - CSR Identity : %s", err, reqIdentity)
191 message := fmt.Sprintf("%s - CSR Identity : %s", err.Error(), reqIdentity)
192 svc.recordEvent(nil, v1.EventTypeWarning, eventTypeFailed, message)
193 return nil, err
194 }
195
196 if err = checkCSR(csr, reqIdentity); err != nil {
197 log.Debugf("requester sent invalid CSR: %s", err)
198 return nil, status.Error(codes.FailedPrecondition, err.Error())
199 }
200
201
202 log.Debugf("Validating token for %s", reqIdentity)
203 tokIdentity, err := svc.validator.Validate(ctx, tok)
204 if err != nil {
205 var nae NotAuthenticated
206 if errors.As(err, &nae) {
207 log.Infof("authentication failed for %s: %s", reqIdentity, nae)
208 return nil, status.Error(codes.FailedPrecondition, nae.Error())
209 }
210 var ite InvalidToken
211 if errors.As(err, &ite) {
212 log.Infof("invalid token provided for %s: %s", reqIdentity, ite)
213 return nil, status.Error(codes.InvalidArgument, ite.Error())
214 }
215
216 msg := fmt.Sprintf("error validating token for %s: %s", reqIdentity, err)
217 log.Error(msg)
218 return nil, status.Error(codes.Internal, msg)
219 }
220
221
222 if reqIdentity != tokIdentity {
223 msg := fmt.Sprintf("requested identity did not match provided token: requested=%s; found=%s",
224 reqIdentity, tokIdentity)
225 log.Info(msg)
226 return nil, status.Error(codes.FailedPrecondition, msg)
227 }
228
229
230 issuer := *svc.issuer
231 crt, err := issuer.IssueEndEntityCrt(csr)
232 if err != nil {
233 return nil, status.Error(codes.Internal, err.Error())
234 }
235 crts := crt.ExtractRaw()
236 if len(crts) == 0 {
237
238 log.Fatal("the issuer provided a certificate without key material")
239 }
240 validUntil := timestamppb.New(crt.Certificate.NotAfter)
241
242 hasher := sha256.New()
243 hasher.Write(crts[0])
244 hash := hex.EncodeToString(hasher.Sum(nil))
245 identitySegments := strings.Split(tokIdentity, ".")
246 msg := fmt.Sprintf("issued certificate for %s until %s: %s", tokIdentity, crt.Certificate.NotAfter, hash)
247 sa := v1.ServiceAccount{
248 ObjectMeta: metav1.ObjectMeta{
249 Name: identitySegments[0],
250 Namespace: identitySegments[1],
251 },
252 }
253 svc.recordEvent(&sa, v1.EventTypeNormal, eventTypeIssuedLeafCert, msg)
254 log.Info(msg)
255
256
257 rsp := &pb.CertifyResponse{
258 LeafCertificate: crts[0],
259 IntermediateCertificates: crts[1:],
260
261 ValidUntil: validUntil,
262 }
263 return rsp, nil
264 }
265
266 func checkRequest(req *pb.CertifyRequest) (string, []byte, *x509.CertificateRequest, error) {
267 reqIdentity := req.GetIdentity()
268 if reqIdentity == "" {
269 return "", nil, nil, errors.New("missing identity")
270 }
271
272 tok := req.GetToken()
273 if len(tok) == 0 {
274 return "", nil, nil, errors.New("missing token")
275 }
276
277 der := req.GetCertificateSigningRequest()
278 if len(der) == 0 {
279 return "", nil, nil,
280 errors.New("missing certificate signing request")
281 }
282 csr, err := x509.ParseCertificateRequest(der)
283 if err != nil {
284 return "", nil, nil, err
285 }
286
287 return reqIdentity, tok, csr, nil
288 }
289
290 func checkCSR(csr *x509.CertificateRequest, identity string) error {
291 if len(csr.DNSNames) != 1 {
292 return errors.New("CSR must have exactly one DNSName")
293 }
294 if csr.DNSNames[0] != identity {
295 return fmt.Errorf("CSR name does not match requested identity: csr=%s; req=%s", csr.DNSNames[0], identity)
296 }
297
298 switch csr.Subject.CommonName {
299 case "", identity:
300 default:
301 return fmt.Errorf("invalid CommonName: %s", csr.Subject.CommonName)
302 }
303
304 if len(csr.EmailAddresses) > 0 {
305 return errors.New("cannot validate email addresses")
306 }
307 if len(csr.IPAddresses) > 0 {
308 return errors.New("cannot validate IP addresses")
309 }
310 if len(csr.URIs) > 0 {
311 return errors.New("cannot validate URIs")
312 }
313
314 return nil
315 }
316
317 func (NotAuthenticated) Error() string {
318 return "authentication token could not be authenticated"
319 }
320
321 func (e InvalidToken) Error() string {
322 return e.Reason
323 }
324
View as plain text