github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/broker/network/choria_auth.go (about) 1 // Copyright (c) 2020-2023, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package network 6 7 import ( 8 "crypto/ed25519" 9 "crypto/md5" 10 "crypto/tls" 11 "encoding/base64" 12 "encoding/hex" 13 "errors" 14 "fmt" 15 "net" 16 "strings" 17 "sync" 18 19 "github.com/choria-io/tokens" 20 "github.com/golang-jwt/jwt/v4" 21 "github.com/nats-io/nats-server/v2/server" 22 "github.com/sirupsen/logrus" 23 24 "github.com/choria-io/go-choria/internal/util" 25 ) 26 27 // ChoriaAuth implements the Nats server.Authentication interface and 28 // allows IP limits to be configured, connections that do not match 29 // the configured IP or CIDRs are not allowed to publish to the 30 // network targets used by clients to request actions on nodes. 31 // 32 // Additionally, when the server is running in a mode where anonymous 33 // TLS connections is accepted then servers are entirely denied and 34 // clients are allowed but restricted based on the JWT issued by the 35 // AAA Service. This is activated using the plugin.choria.network.client_anon_tls 36 // setting, however this should be avoided atm. 37 // 38 // Clients can present a JWT token signed by the AAA service if that 39 // token has a purpose field matching choria_client_id and if the 40 // AAA signer is configured in the broker using plugin.choria.security.request_signing_certificate 41 // those with valid tokens and that are fully verified can connect but 42 // will be restricted to client only functions. These clients will not 43 // be able to access any Choria Streams features, KV buckets etc 44 // 45 // Additionally when provisioning support is enabled any non mTLS connection 46 // will be placed in the provisioning account and unable to connect to the 47 // fleet or provisioned nodes. This is only enabled if plugin.choria.network.provisioning.signer_cert 48 // is set 49 type ChoriaAuth struct { 50 clientAllowList []string 51 isTLS bool 52 denyServers bool 53 provisioningTokenSigner string 54 clientJwtSigners []string 55 serverJwtSigners []string 56 allowIssuerBasedTLSAccess bool 57 issuerTokens map[string]string 58 choriaAccount *server.Account 59 systemAccount *server.Account 60 provisioningAccount *server.Account 61 provPass string 62 provWithoutToken bool 63 systemUser string 64 systemPass string 65 tokenCache map[string]ed25519.PublicKey 66 log *logrus.Entry 67 mu sync.Mutex 68 } 69 70 const ( 71 provisioningUser = "provisioner" 72 emptyString = "" 73 edDSASigningMethod = "EdDSA" 74 ) 75 76 var allSubjects = []string{">"} 77 78 // Check checks and registers the incoming connection 79 func (a *ChoriaAuth) Check(c server.ClientAuthentication) bool { 80 var ( 81 verified bool 82 tlsVerified bool 83 err error 84 ) 85 86 log := a.log.WithField("stage", "check") 87 remote := c.RemoteAddress() 88 if remote != nil { 89 log = log.WithField("remote", remote.String()) 90 } 91 pipeConnection := remote.String() == "pipe" 92 93 tlsc := c.GetTLSConnectionState() 94 if tlsc != nil { 95 tlsVerified = len(tlsc.VerifiedChains) > 0 96 } 97 98 // no tls over pipes 99 if !pipeConnection && a.isTLS && tlsc == nil { 100 a.log.Warnf("Did not receive TLS Connection State for connection %s, rejecting", remote) 101 return false 102 } 103 104 systemUser := a.isSystemUser(c) 105 106 switch { 107 case a.isProvisionUser(c): 108 verified, err = a.handleProvisioningUserConnection(c, tlsVerified) 109 if err != nil { 110 log.Warnf("Handling provisioning user connection failed, denying %s: %s", c.RemoteAddress().String(), err) 111 } 112 113 case systemUser && (tlsVerified || pipeConnection): 114 verified, err = a.handleVerifiedSystemAccount(c, log) 115 if err != nil { 116 log.Warnf("Handling system user failed, denying: %s", err) 117 } 118 119 case systemUser && tlsc == nil: 120 verified = false 121 log.Warnf("System user is only allowed over TLS connections") 122 123 case systemUser && !tlsVerified: 124 verified, err = a.handleUnverifiedSystemAccount(c, tlsc, log) 125 if err != nil { 126 log.Warnf("Handling unverified TLS system user failed, denying: %s", err) 127 } 128 129 default: 130 var dfltErr, provErr error 131 132 verified, dfltErr = a.handleDefaultConnection(c, tlsc, tlsVerified, log) 133 if !verified && a.isTLS && !tlsVerified { 134 verified, provErr = a.handleUnverifiedProvisioningConnection(c) 135 } 136 137 if !verified { 138 log.Warnf("Denying connection: verified error: %v, unverified error: %v", dfltErr, provErr) 139 } 140 } 141 142 // should be already but let's make sure 143 if err != nil { 144 verified = false 145 } 146 147 return verified 148 } 149 150 func (a *ChoriaAuth) verifyNonceSignature(nonce []byte, sig string, pks string, log *logrus.Entry) (bool, error) { 151 if sig == "" { 152 return false, fmt.Errorf("connection nonce was not signed") 153 } 154 155 if pks == "" { 156 return false, fmt.Errorf("no public key found in the JWT to verify nonce signature") 157 } 158 159 if len(nonce) == 0 { 160 return false, fmt.Errorf("server did not generate a nonce to verify") 161 } 162 163 pubK, err := hex.DecodeString(pks) 164 if err != nil { 165 return false, fmt.Errorf("invalid nonce signature") 166 } 167 168 sigBytes, err := base64.RawURLEncoding.DecodeString(sig) 169 if err != nil { 170 return false, fmt.Errorf("invalid url encoded signature: %s", err) 171 } 172 173 valid, err := a.ed25519Verify(pubK, nonce, sigBytes) 174 if err != nil { 175 return false, fmt.Errorf("could not verify nonce signature: %v", err) 176 } 177 178 if !valid { 179 return false, fmt.Errorf("nonce signature did not verify using pub key in the jwt") 180 } 181 182 log.Debugf("Successfully verified nonce signature") 183 184 return true, nil 185 } 186 187 // ed25519.Sha256VerifyDir() panics on bad pubkeys, this does not 188 func (a *ChoriaAuth) ed25519Verify(publicKey ed25519.PublicKey, message []byte, sig []byte) (bool, error) { 189 if len(publicKey) != ed25519.PublicKeySize { 190 return false, fmt.Errorf("invalid public key length %d", len(publicKey)) 191 } 192 193 return ed25519.Verify(publicKey, message, sig), nil 194 } 195 196 func (a *ChoriaAuth) verifyServerJWTBasedAuth(remote net.Addr, jwts string, nonce []byte, sig string, log *logrus.Entry) (claims *tokens.ServerClaims, err error) { 197 if remote == nil { 198 log.Errorf("no remote client information received") 199 return nil, fmt.Errorf("remote client information is required in anonymous TLS or JWT signing modes") 200 } 201 202 claims, err = a.parseServerJWT(jwts) 203 if err != nil { 204 log.Errorf("could not parse JWT from %s: %s", remote.String(), err) 205 return nil, fmt.Errorf("invalid JWT token") 206 } 207 208 _, err = a.verifyNonceSignature(nonce, sig, claims.PublicKey, log) 209 if err != nil { 210 log.Errorf("nonce signature verification failed: %s", err) 211 return nil, fmt.Errorf("invalid nonce signature") 212 } 213 214 return claims, nil 215 } 216 217 func (a *ChoriaAuth) verifyClientJWTBasedAuth(remote net.Addr, jwts string, nonce []byte, sig string, log *logrus.Entry) (claims *tokens.ClientIDClaims, err error) { 218 if remote == nil { 219 log.Errorf("no remote connection details received") 220 return nil, fmt.Errorf("remote client information is required in anonymous TLS or JWT signing modes") 221 } 222 223 claims, err = a.parseClientIDJWT(jwts) 224 if err != nil { 225 log.Errorf("could not parse JWT from %s: %s", remote.String(), err) 226 return nil, fmt.Errorf("invalid JWT token") 227 } 228 229 _, err = a.verifyNonceSignature(nonce, sig, claims.PublicKey, log) 230 if err != nil { 231 log.Errorf("nonce signature verification failed: %s", err) 232 return nil, fmt.Errorf("invalid nonce signature") 233 } 234 235 return claims, nil 236 } 237 238 func (a *ChoriaAuth) handleDefaultConnection(c server.ClientAuthentication, conn *tls.ConnectionState, tlsVerified bool, log *logrus.Entry) (bool, error) { 239 user := a.createUser(c) 240 remote := c.RemoteAddress() 241 opts := c.GetOpts() 242 nonce := c.GetNonce() 243 jwts := opts.Token 244 caller := "" 245 pipeConnection := remote.String() == "pipe" 246 247 var err error 248 249 log = log.WithField("mTLS", tlsVerified) 250 log = log.WithField("name", opts.Name) 251 if pipeConnection { 252 log = log.WithField("pipe", true) 253 } 254 255 if tlsVerified && len(conn.PeerCertificates) > 0 { 256 log = log.WithField("subject", conn.PeerCertificates[0].Subject.CommonName) 257 } 258 if user.Account != nil { 259 log = log.WithField("account", user.Account.Name) 260 } 261 262 var ( 263 serverClaims *tokens.ServerClaims 264 clientClaims *tokens.ClientIDClaims 265 setClientPerms bool 266 setServerPerms bool 267 ) 268 269 shouldPerformJWTBasedAuth := jwts != emptyString && conn != nil 270 if shouldPerformJWTBasedAuth { 271 purpose := tokens.TokenPurpose(jwts) 272 log = log.WithFields(logrus.Fields{"jwt_auth": shouldPerformJWTBasedAuth, "purpose": purpose}) 273 log.Debugf("Performing JWT based authentication verification") 274 275 switch purpose { 276 case tokens.ClientIDPurpose: 277 if c.Kind() != server.CLIENT { 278 return false, fmt.Errorf("a client JWT was presented by a %d connection", c.Kind()) 279 } 280 281 clientClaims, err = a.verifyClientJWTBasedAuth(remote, jwts, nonce, opts.Sig, log) 282 if err != nil { 283 return false, fmt.Errorf("invalid nonce signature or jwt token") 284 } 285 log = log.WithField("caller", clientClaims.CallerID) 286 log.Debugf("Extracted caller id %s from JWT token", clientClaims.CallerID) 287 288 caller = clientClaims.CallerID 289 setClientPerms = true 290 user.Username = caller 291 292 case tokens.ServerPurpose: 293 if c.Kind() != server.CLIENT { 294 return false, fmt.Errorf("a server JWT was presented by a %d connection", c.Kind()) 295 } 296 297 serverClaims, err = a.verifyServerJWTBasedAuth(remote, jwts, nonce, opts.Sig, log) 298 if err != nil { 299 return false, fmt.Errorf("invalid nonce signature or jwt token") 300 } 301 log = log.WithField("identity", serverClaims.ChoriaIdentity) 302 log.Debugf("Extracted remote identity %s from JWT token", serverClaims.ChoriaIdentity) 303 304 setServerPerms = true 305 user.Username = serverClaims.ChoriaIdentity 306 307 default: 308 return false, fmt.Errorf("do not know how to handle %v purpose token", purpose) 309 } 310 } 311 312 switch { 313 case !shouldPerformJWTBasedAuth && !tlsVerified && !pipeConnection: 314 log.Warnf("Rejecting unverified connection without token") 315 return false, fmt.Errorf("unverified connection without JWT token") 316 317 // if a caller is set from the Client ID JWT we want to restrict it to just client stuff 318 // if a client allow list is set and the client is in the ip range we restrict it also 319 // else its default open like users with certs 320 case setClientPerms || (!setServerPerms && caller != "" && a.remoteInClientAllowList(remote)): 321 log.Debugf("Setting client permissions") 322 a.setClientPermissions(user, caller, clientClaims, log) 323 324 // Else in the case where an allow list is configured we set server permissions on other conns 325 case setServerPerms || len(a.clientAllowList) > 0: 326 a.setServerPermissions(user, serverClaims, log) 327 328 case pipeConnection: 329 log.Debugf("Allowing pipe connection without any limitations") 330 331 case tlsVerified && a.allowIssuerBasedTLSAccess: 332 log.Debugf("Allowing pub-sub access") 333 a.setPubSubPermissions(user) 334 335 case len(a.issuerTokens) > 0: 336 // In issuer mode unless mTLS is in use we do not want to allow any access to any kind of standard nats connection 337 // it should be really hard to reach this code at this point, I can't think of a case, but we handle the deny all 338 // for safety here 339 // 340 // to allow pub-sub access users must set a CA (enables mTLS) and connections must be mTLS which will mean allowIssuerBasedTLSAccess 341 // is true. 342 return false, fmt.Errorf("unknown connection received in issuer mode") 343 344 default: 345 // non issuer mode handled non client || server connections as an allow all 346 log.Debugf("Unknown connection type, allowing without restriction for legacy access") 347 } 348 349 if user.Account != nil { 350 log.Debugf("Registering user '%s' in account '%s'", user.Username, user.Account.Name) 351 } else { 352 log.Debugf("Registering user '%s' in default account", user.Username) 353 } 354 355 c.RegisterUser(user) 356 357 return true, nil 358 } 359 360 func (a *ChoriaAuth) handleUnverifiedSystemAccount(c server.ClientAuthentication, conn *tls.ConnectionState, log *logrus.Entry) (bool, error) { 361 if conn == nil { 362 return false, fmt.Errorf("requires TLS") 363 } 364 365 remote := c.RemoteAddress() 366 opts := c.GetOpts() 367 jwts := opts.Token 368 369 if jwts == emptyString { 370 return false, fmt.Errorf("no JWT token received") 371 } 372 373 purpose := tokens.TokenPurpose(jwts) 374 log = log.WithFields(logrus.Fields{"jwt_auth": true, "purpose": purpose, "name": opts.Name}) 375 log.Debugf("Performing JWT based authentication verification for system account access") 376 377 if purpose != tokens.ClientIDPurpose { 378 return false, fmt.Errorf("client token required") 379 } 380 381 if c.Kind() != server.CLIENT { 382 return false, fmt.Errorf("a client JWT was presented by a %d connection", c.Kind()) 383 } 384 385 claims, err := a.parseClientIDJWT(jwts) 386 if err != nil { 387 log.Errorf("could not parse JWT from %s: %s", remote.String(), err) 388 return false, fmt.Errorf("invalid JWT token") 389 } 390 391 if claims.Permissions == nil || !(claims.Permissions.SystemUser || claims.Permissions.OrgAdmin) { 392 return false, fmt.Errorf("no system_user or org_admin claim") 393 } 394 395 nonce := c.GetNonce() 396 _, err = a.verifyNonceSignature(nonce, opts.Sig, claims.PublicKey, log) 397 if err != nil { 398 log.Errorf("nonce signature verification failed: %s", err) 399 return false, fmt.Errorf("invalid nonce signature") 400 } 401 402 return a.handleVerifiedSystemAccount(c, log) 403 } 404 405 func (a *ChoriaAuth) handleVerifiedSystemAccount(c server.ClientAuthentication, log *logrus.Entry) (bool, error) { 406 if a.systemUser == "" { 407 return false, fmt.Errorf("system user is required") 408 } 409 410 if a.systemPass == "" { 411 return false, fmt.Errorf("system password is required") 412 } 413 414 if a.systemAccount == nil { 415 return false, fmt.Errorf("system account is not set") 416 } 417 418 opts := c.GetOpts() 419 420 if !(opts.Username == a.systemUser && opts.Password == a.systemPass) { 421 return false, fmt.Errorf("invalid system credentials") 422 } 423 424 user := a.createUser(c) 425 user.Account = a.systemAccount 426 427 log.Debugf("Registering user '%s' in account '%s'", user.Username, user.Account.Name) 428 c.RegisterUser(user) 429 430 return true, nil 431 } 432 433 func (a *ChoriaAuth) handleProvisioningUserConnectionWithIssuer(c server.ClientAuthentication) (bool, error) { 434 opts := c.GetOpts() 435 436 if opts.Token == "" && !a.provWithoutToken { 437 return false, fmt.Errorf("no token provided in connection") 438 } 439 440 if opts.Token != "" { 441 claims, err := a.parseClientIDJWTWithIssuer(opts.Token) 442 if err != nil { 443 return false, err 444 } 445 446 if claims.Permissions == nil || !claims.Permissions.ServerProvisioner { 447 return false, fmt.Errorf("provisioner claim is false in token with caller id '%s'", claims.CallerID) 448 } 449 } 450 451 user := a.createUser(c) 452 user.Account = a.provisioningAccount 453 454 a.log.Debugf("Registering user '%s' in account '%s' from claims with", user.Username, user.Account.Name) 455 c.RegisterUser(user) 456 457 return true, nil 458 } 459 460 func (a *ChoriaAuth) handleProvisioningUserConnectionWithTLS(c server.ClientAuthentication, tlsVerified bool) (bool, error) { 461 if !tlsVerified { 462 return false, fmt.Errorf("provisioning user is only allowed over verified TLS connections") 463 } 464 465 if !a.isTLS { 466 return false, fmt.Errorf("provisioning user access requires TLS") 467 } 468 469 if c.GetTLSConnectionState() == nil { 470 return false, fmt.Errorf("provisioning user can only connect over tls") 471 } 472 473 user := a.createUser(c) 474 user.Account = a.provisioningAccount 475 476 a.log.Debugf("Registering user '%s' in account '%s'", user.Username, user.Account.Name) 477 c.RegisterUser(user) 478 479 return true, nil 480 } 481 482 func (a *ChoriaAuth) handleProvisioningUserConnection(c server.ClientAuthentication, tlsVerified bool) (bool, error) { 483 if a.provPass == emptyString { 484 return false, fmt.Errorf("provisioning user password not enabled") 485 } 486 487 if a.provisioningAccount == nil { 488 return false, fmt.Errorf("provisioning account is not set") 489 } 490 491 opts := c.GetOpts() 492 493 if opts.Password == emptyString { 494 return false, fmt.Errorf("password required") 495 } 496 497 if a.provPass != opts.Password { 498 return false, fmt.Errorf("invalid provisioner password supplied") 499 } 500 501 if len(a.issuerTokens) > 0 { 502 return a.handleProvisioningUserConnectionWithIssuer(c) 503 } 504 505 return a.handleProvisioningUserConnectionWithTLS(c, tlsVerified) 506 } 507 508 func (a *ChoriaAuth) handleUnverifiedProvisioningConnectionWithIssuer(c server.ClientAuthentication, opts *server.ClientOpts) (bool, error) { 509 if a.provPass == emptyString { 510 return false, fmt.Errorf("provisioning is not enabled") 511 } 512 513 user := a.createUser(c) 514 user.Account = a.provisioningAccount 515 516 uclaims, err := tokens.ParseTokenUnverified(opts.Token) 517 if err != nil { 518 return false, err 519 } 520 521 ou := uclaims["ou"] 522 if ou == nil { 523 return false, fmt.Errorf("no ou claim in token") 524 } 525 526 ous, ok := ou.(string) 527 if !ok { 528 return false, fmt.Errorf("invald ou in token") 529 } 530 531 issuer, ok := a.issuerTokens[ous] 532 if !ok { 533 return false, fmt.Errorf("no issuer found for ou %s", ous) 534 } 535 536 pk, err := a.cachedEd25519Token(issuer) 537 if err != nil { 538 return false, fmt.Errorf("invalid issuer public key: %w", err) 539 } 540 541 _, err = tokens.ParseProvisioningToken(opts.Token, pk) 542 if err != nil { 543 return false, err 544 } 545 546 a.log.Debugf("Allowing a provisioning server from using issuer '%s' connecting from %s", ous, c.RemoteAddress().String()) 547 548 // anything that get this far has to be a server and so we unconditionally set server 549 // only permissions, and only to agents provisioning would bother hosting. 550 // 551 // We also allow provisioning.registration.> to allow a mode where prov mode servers 552 // would be publishing some known metadata, by convention, this is the only place they 553 // can publish to 554 a.setProvisioningServerPermissions(user) 555 556 a.log.Debugf("Registering user '%s' in account '%s'", user.Username, user.Account.Name) 557 c.RegisterUser(user) 558 559 return true, nil 560 } 561 562 func (a *ChoriaAuth) handleUnverifiedProvisioningConnectionWithTLS(c server.ClientAuthentication, opts *server.ClientOpts) (bool, error) { 563 if a.provisioningTokenSigner == emptyString { 564 return false, fmt.Errorf("provisioning is not enabled") 565 } 566 567 if !util.FileExist(a.provisioningTokenSigner) { 568 return false, fmt.Errorf("provisioning signer certificate %s does not exist", a.provisioningTokenSigner) 569 } 570 571 user := a.createUser(c) 572 user.Account = a.provisioningAccount 573 574 _, err := tokens.ParseProvisioningTokenWithKeyfile(opts.Token, a.provisioningTokenSigner) 575 if err != nil { 576 return false, err 577 } 578 579 a.log.Debugf("Allowing a provisioning server from using unverified TLS connection from %s", c.RemoteAddress().String()) 580 581 // anything that get this far has to be a server and so we unconditionally set server 582 // only permissions, and only to agents provisioning would bother hosting. 583 // 584 // We also allow provisioning.registration.> to allow a mode where prov mode servers 585 // would be publishing some known metadata, by convention, this is the only place they 586 // can publish to 587 a.setProvisioningServerPermissions(user) 588 589 a.log.Debugf("Registering user '%s' in account '%s'", user.Username, user.Account.Name) 590 c.RegisterUser(user) 591 592 return true, nil 593 } 594 595 func (a *ChoriaAuth) setProvisioningServerPermissions(user *server.User) { 596 user.Permissions.Subscribe = &server.SubjectPermission{ 597 Allow: []string{ 598 "provisioning.node.>", 599 "provisioning.broadcast.agent.discovery", 600 "provisioning.broadcast.agent.rpcutil", 601 "provisioning.broadcast.agent.choria_util", 602 "provisioning.broadcast.agent.choria_provision", 603 }, 604 } 605 606 user.Permissions.Publish = &server.SubjectPermission{ 607 Allow: []string{ 608 "choria.lifecycle.>", 609 "provisioning.reply.>", 610 "provisioning.registration.>", 611 }, 612 } 613 } 614 615 func (a *ChoriaAuth) handleUnverifiedProvisioningConnection(c server.ClientAuthentication) (bool, error) { 616 if a.provisioningAccount == nil { 617 return false, fmt.Errorf("provisioning account is not set") 618 } 619 620 opts := c.GetOpts() 621 if opts.Username == provisioningUser { 622 return false, fmt.Errorf("provisioning user requires a verified connection") 623 } 624 625 if opts.Token == emptyString { 626 return false, fmt.Errorf("provisioning requires a token") 627 } 628 629 // we only handle ed25519 signed tokens as issuer tokens 630 // since we support also provisioning v1 nodes we have to 631 // assume those might have rsa signatures - v2 ones never 632 // 633 // so we restrict the issuer based validation to ones with ed25519 634 // based signatures 635 alg, err := tokens.TokenSigningAlgorithm(opts.Token) 636 if err != nil { 637 return false, fmt.Errorf("could not determine token algorithm: %v", err) 638 } 639 640 if alg == edDSASigningMethod && len(a.issuerTokens) > 0 { 641 return a.handleUnverifiedProvisioningConnectionWithIssuer(c, opts) 642 } 643 644 return a.handleUnverifiedProvisioningConnectionWithTLS(c, opts) 645 } 646 647 func (a *ChoriaAuth) cachedEd25519Token(token string) (ed25519.PublicKey, error) { 648 a.mu.Lock() 649 defer a.mu.Unlock() 650 651 if a.tokenCache == nil { 652 a.tokenCache = make(map[string]ed25519.PublicKey) 653 } 654 655 pk, ok := a.tokenCache[token] 656 if !ok { 657 tok, err := hex.DecodeString(token) 658 if err != nil { 659 return nil, err 660 } 661 a.tokenCache[token] = tok 662 pk = tok 663 } 664 665 return pk, nil 666 } 667 668 func (a *ChoriaAuth) parseServerJWTWithSigners(jwts string) (claims *tokens.ServerClaims, err error) { 669 for _, s := range a.serverJwtSigners { 670 // its a token 671 if util.IsEncodedEd25519KeyString(s) { 672 var pk ed25519.PublicKey 673 pk, err = a.cachedEd25519Token(s) 674 if err != nil { 675 continue 676 } 677 claims, err = tokens.ParseServerToken(jwts, pk) 678 } else { 679 claims, err = tokens.ParseServerTokenWithKeyfile(jwts, s) 680 } 681 682 switch { 683 case len(a.serverJwtSigners) == 1 && err != nil: 684 // just a bit friendlier than saying a generic error with 1 failure 685 return nil, err 686 case errors.Is(err, jwt.ErrTokenExpired), errors.Is(err, tokens.ErrNotAServerToken): 687 // These are fatal errors that no further trying will resolve 688 return nil, err 689 case err != nil: 690 continue 691 } 692 693 break 694 } 695 if err != nil { 696 return nil, fmt.Errorf("could not parse server token with any of %d signer identities", len(a.serverJwtSigners)) 697 } 698 699 return claims, nil 700 } 701 702 func (a *ChoriaAuth) parseServerJWTWithIssuer(jwts string) (claims *tokens.ServerClaims, err error) { 703 uclaims, err := tokens.ParseTokenUnverified(jwts) 704 if err != nil { 705 return nil, err 706 } 707 708 ou := uclaims["ou"] 709 if ou == nil { 710 return nil, fmt.Errorf("no ou claim in token") 711 } 712 713 ous, ok := ou.(string) 714 if !ok { 715 return nil, fmt.Errorf("invald ou in token") 716 } 717 718 issuer, ok := a.issuerTokens[ous] 719 if !ok { 720 return nil, fmt.Errorf("no issuer found for ou %s", ous) 721 } 722 723 pk, err := a.cachedEd25519Token(issuer) 724 if err != nil { 725 return nil, fmt.Errorf("invalid issuer public key: %w", err) 726 } 727 728 claims, err = tokens.ParseServerToken(jwts, pk) 729 if err != nil { 730 return nil, fmt.Errorf("failed to parse token issued by the %s chain: %w", ous, err) 731 } 732 733 return claims, nil 734 } 735 736 func (a *ChoriaAuth) parseServerJWT(jwts string) (claims *tokens.ServerClaims, err error) { 737 if len(a.serverJwtSigners) == 0 && len(a.issuerTokens) == 0 { 738 return nil, fmt.Errorf("no Server JWT signer or Organization Issuer set, denying all servers") 739 } 740 741 if jwts == emptyString { 742 return nil, fmt.Errorf("no JWT received") 743 } 744 745 // if we have issuer tokens we get the org from the token and then check it using the issuer for the org 746 if len(a.issuerTokens) > 0 { 747 claims, err = a.parseServerJWTWithIssuer(jwts) 748 if err != nil { 749 return nil, err 750 } 751 } else { 752 // if no issuer we would have signers so we check them all 753 claims, err = a.parseServerJWTWithSigners(jwts) 754 if err != nil { 755 return nil, err 756 } 757 } 758 759 if claims.ChoriaIdentity == emptyString { 760 return nil, fmt.Errorf("identity not in claims") 761 } 762 763 if claims.PublicKey == emptyString { 764 return nil, fmt.Errorf("no public key in claims") 765 } 766 767 return claims, nil 768 } 769 770 func (a *ChoriaAuth) parseClientJWTWithSigners(jwts string) (claims *tokens.ClientIDClaims, err error) { 771 for _, s := range a.clientJwtSigners { 772 // its a token 773 if util.IsEncodedEd25519KeyString(s) { 774 var pk ed25519.PublicKey 775 pk, err = a.cachedEd25519Token(s) 776 if err != nil { 777 continue 778 } 779 claims, err = tokens.ParseClientIDToken(jwts, pk, true) 780 } else { 781 claims, err = tokens.ParseClientIDTokenWithKeyfile(jwts, s, true) 782 } 783 784 switch { 785 case len(a.clientJwtSigners) == 1 && err != nil: 786 // just a bit friendlier than saying a generic error with 1 failure 787 return nil, err 788 case errors.Is(err, jwt.ErrTokenExpired), errors.Is(err, tokens.ErrNotAClientToken), errors.Is(err, tokens.ErrInvalidClientCallerID): 789 // these will tend to fail on every parse, so we try to catch them early and just error when we first hit them 790 return nil, err 791 case err != nil: 792 // we try the next 793 continue 794 } 795 796 break 797 } 798 // above we try to the last, if we still have an error here it failed 799 if err != nil { 800 return nil, fmt.Errorf("could not parse client token with any of %d signer identities", len(a.clientJwtSigners)) 801 } 802 803 return claims, nil 804 } 805 806 func (a *ChoriaAuth) parseClientIDJWTWithIssuer(jwts string) (claims *tokens.ClientIDClaims, err error) { 807 uclaims, err := tokens.ParseTokenUnverified(jwts) 808 if err != nil { 809 return nil, err 810 } 811 812 ou := uclaims["ou"] 813 if ou == nil { 814 return nil, fmt.Errorf("no ou claim in token") 815 } 816 817 ous, ok := ou.(string) 818 if !ok { 819 return nil, fmt.Errorf("invald ou in token") 820 } 821 822 issuer, ok := a.issuerTokens[ous] 823 if !ok { 824 return nil, fmt.Errorf("no issuer configured for ou '%s'", ous) 825 } 826 827 pk, err := a.cachedEd25519Token(issuer) 828 if err != nil { 829 return nil, fmt.Errorf("invalid issuer public key: %w", err) 830 } 831 832 claims, err = tokens.ParseClientIDToken(jwts, pk, true) 833 if err != nil { 834 return nil, fmt.Errorf("failed to parse client token issued by the %s chain: %w", ous, err) 835 } 836 837 return claims, nil 838 } 839 840 func (a *ChoriaAuth) parseClientIDJWT(jwts string) (claims *tokens.ClientIDClaims, err error) { 841 if len(a.clientJwtSigners) == 0 && len(a.issuerTokens) == 0 { 842 return nil, fmt.Errorf("no Client JWT signer or Organization Issuer set, denying all clients") 843 } 844 845 if jwts == emptyString { 846 return nil, fmt.Errorf("no JWT received") 847 } 848 849 // if we have issuer tokens we get the org from the token and then check it using the issuer for the org 850 if len(a.issuerTokens) > 0 { 851 claims, err = a.parseClientIDJWTWithIssuer(jwts) 852 } else { 853 // else we have signers so lets check using those 854 claims, err = a.parseClientJWTWithSigners(jwts) 855 } 856 if err != nil { 857 return nil, err 858 } 859 860 if claims.CallerID == emptyString { 861 return nil, fmt.Errorf("no callerid in claims") 862 } 863 864 if claims.PublicKey == emptyString { 865 return nil, fmt.Errorf("no public key in claims") 866 } 867 868 return claims, nil 869 } 870 871 func (a *ChoriaAuth) setClientFleetManagementPermissions(subs []string, pubs []string) ([]string, []string) { 872 pubs = append(pubs, 873 "*.broadcast.agent.>", 874 "*.broadcast.service.>", 875 "*.node.>", 876 "choria.federation.*.federation", 877 ) 878 879 return subs, pubs 880 } 881 882 func (a *ChoriaAuth) setMinimalClientPermissions(_ *server.User, caller string, subs []string, pubs []string) ([]string, []string) { 883 replys := "*.reply.>" 884 if caller != emptyString { 885 replys = fmt.Sprintf("*.reply.%x.>", md5.Sum([]byte(caller))) 886 a.log.Debugf("Creating ACLs for a private reply subject on %s", replys) 887 } 888 889 subs = append(subs, replys) 890 pubs = append(pubs, "$SYS.REQ.USER.INFO") 891 892 return subs, pubs 893 } 894 895 func (a *ChoriaAuth) setStreamsAdminPermissions(user *server.User, subs []string, pubs []string) ([]string, []string) { 896 if user.Account != a.choriaAccount { 897 return subs, pubs 898 } 899 900 subs = append(subs, "$JS.EVENT.>") 901 pubs = append(pubs, "$JS.>") 902 903 return subs, pubs 904 } 905 906 func (a *ChoriaAuth) setStreamsUserPermissions(user *server.User, subs []string, pubs []string) ([]string, []string) { 907 if user.Account != a.choriaAccount { 908 return subs, pubs 909 } 910 911 pubs = append(pubs, 912 "$JS.API.INFO", 913 "$JS.API.STREAM.NAMES", 914 "$JS.API.STREAM.LIST", 915 "$JS.API.STREAM.INFO.*", 916 "$JS.API.STREAM.MSG.GET.*", 917 "$JS.API.STREAM.MSG.DELETE.*", 918 "$JS.API.DIRECT.GET.*", 919 "$JS.API.DIRECT.GET.*.>", 920 "$JS.API.CONSUMER.CREATE.*", 921 "$JS.API.CONSUMER.CREATE.*.>", 922 "$JS.API.CONSUMER.DURABLE.CREATE.*.*", 923 "$JS.API.CONSUMER.DELETE.*.*", 924 "$JS.API.CONSUMER.NAMES.*", 925 "$JS.API.CONSUMER.LIST.*", 926 "$JS.API.CONSUMER.INFO.*.*", 927 "$JS.API.CONSUMER.MSG.NEXT.*.*", 928 "$JS.ACK.>", 929 "$JS.FC.>", 930 "$KV.>", 931 "$O.>", 932 ) 933 934 return subs, pubs 935 } 936 937 func (a *ChoriaAuth) setEventsViewerPermissions(user *server.User, subs []string, pubs []string) ([]string, []string) { 938 switch user.Account { 939 case a.choriaAccount: 940 subs = append(subs, 941 "choria.lifecycle.event.>", 942 "choria.machine.watcher.>", 943 "choria.machine.transition") 944 case a.provisioningAccount: 945 // provisioner should only listen to one specific kind of event, not strictly needed but its what it is 946 subs = append(subs, "choria.lifecycle.event.*.provision_mode_server") 947 } 948 949 return subs, pubs 950 } 951 952 func (a *ChoriaAuth) setClientGovernorPermissions(user *server.User, subs []string, pubs []string) ([]string, []string) { 953 if user.Account != a.choriaAccount { 954 return subs, pubs 955 } 956 957 pubs = append(pubs, "*.governor.*") 958 pubs = append(pubs, "choria.lifecycle.event.governor.>") 959 960 return subs, pubs 961 } 962 963 func (a *ChoriaAuth) setElectionPermissions(user *server.User, subs []string, pubs []string) ([]string, []string) { 964 switch user.Account { 965 case a.choriaAccount: 966 pubs = append(pubs, 967 "$JS.API.STREAM.INFO.KV_CHORIA_LEADER_ELECTION", 968 "$KV.CHORIA_LEADER_ELECTION.>") 969 case a.provisioningAccount: 970 // provisioner account is special and can only access one very specific election 971 pubs = append(pubs, 972 "choria.streams.STREAM.INFO.KV_CHORIA_LEADER_ELECTION", 973 "$KV.CHORIA_LEADER_ELECTION.provisioner") 974 } 975 976 return subs, pubs 977 } 978 979 func (a *ChoriaAuth) setClientTokenPermissions(user *server.User, caller string, client *tokens.ClientIDClaims, log *logrus.Entry) (pubs []string, subs []string, pubsDeny []string, subsDeny []string, err error) { 980 var perms *tokens.ClientPermissions 981 982 if client != nil { 983 perms = client.Permissions 984 } 985 986 if perms != nil && perms.OrgAdmin { 987 log.Infof("Granting user access to all subjects (OrgAdmin)") 988 return allSubjects, allSubjects, nil, nil, nil 989 } 990 991 subs, pubs = a.setMinimalClientPermissions(user, caller, subs, pubs) 992 993 if client != nil { 994 subs = append(subs, client.AdditionalSubscribeSubjects...) 995 pubs = append(pubs, client.AdditionalPublishSubjects...) 996 } 997 998 if perms != nil { 999 var matched bool 1000 1001 // Can access full Streams Features 1002 if perms.StreamsAdmin { 1003 log.Debugf("Granting user Streams Admin access") 1004 matched = true 1005 subs, pubs = a.setStreamsAdminPermissions(user, subs, pubs) 1006 } 1007 1008 // Can use streams but not make new ones etc 1009 if perms.StreamsUser { 1010 log.Debugf("Granting user Streams User access") 1011 matched = true 1012 subs, pubs = a.setStreamsUserPermissions(user, subs, pubs) 1013 } 1014 1015 // Lifecycle and auto agent events 1016 if perms.EventsViewer { 1017 log.Debugf("Granting user Events Viewer access") 1018 matched = true 1019 subs, pubs = a.setEventsViewerPermissions(user, subs, pubs) 1020 } 1021 1022 // KV based elections 1023 if perms.ElectionUser { 1024 log.Debugf("Granting user Leader Election access") 1025 matched = true 1026 subs, pubs = a.setElectionPermissions(user, subs, pubs) 1027 } 1028 1029 if perms.Governor && (perms.StreamsUser || perms.StreamsAdmin) { 1030 log.Debugf("Granting user Governor access") 1031 matched = true 1032 subs, pubs = a.setClientGovernorPermissions(user, subs, pubs) 1033 } 1034 1035 if perms.FleetManagement || perms.SignedFleetManagement { 1036 log.Debugf("Granting user fleet management access") 1037 matched = true 1038 subs, pubs = a.setClientFleetManagementPermissions(subs, pubs) 1039 } 1040 1041 if !matched { 1042 if len(subs) == 0 { 1043 subsDeny = allSubjects 1044 } 1045 if len(pubs) == 0 { 1046 pubsDeny = allSubjects 1047 } 1048 } 1049 } 1050 1051 // we only lock down the choria account on deny all basis, not relevant today, but eventually we hope to use accounts more 1052 if user.Account == a.choriaAccount { 1053 // when an allow list is given and no deny, deny is implied. But no allow means deny is also wide open, so this handles that case 1054 if len(pubs) == 0 { 1055 pubsDeny = allSubjects 1056 } 1057 if len(subs) == 0 { 1058 subsDeny = allSubjects 1059 } 1060 } 1061 1062 return pubs, subs, pubsDeny, subsDeny, nil 1063 } 1064 1065 func (a *ChoriaAuth) setClientPermissions(user *server.User, caller string, client *tokens.ClientIDClaims, log *logrus.Entry) { 1066 user.Permissions.Subscribe = &server.SubjectPermission{} 1067 user.Permissions.Publish = &server.SubjectPermission{} 1068 1069 pubs, subs, pubDeny, subDeny, err := a.setClientTokenPermissions(user, caller, client, log) 1070 if err != nil { 1071 log.Warnf("Could not determine permissions for user, denying all: %s", err) 1072 user.Permissions.Subscribe.Deny = allSubjects 1073 user.Permissions.Publish.Deny = allSubjects 1074 } else { 1075 user.Permissions.Subscribe.Allow = subs 1076 user.Permissions.Subscribe.Deny = subDeny 1077 user.Permissions.Publish.Allow = pubs 1078 user.Permissions.Publish.Deny = pubDeny 1079 } 1080 1081 log.Debugf("Setting sub permissions: %#v", user.Permissions.Subscribe) 1082 log.Debugf("Setting pub permissions: %#v", user.Permissions.Publish) 1083 if user.Permissions.Response != nil { 1084 log.Debugf("Setting resp permissions: %#v", user.Permissions.Response) 1085 } 1086 } 1087 1088 func (a *ChoriaAuth) setDenyServersPermissions(user *server.User) { 1089 user.Permissions.Subscribe = &server.SubjectPermission{ 1090 Deny: allSubjects, 1091 } 1092 1093 user.Permissions.Publish = &server.SubjectPermission{ 1094 Deny: allSubjects, 1095 } 1096 } 1097 1098 func (a *ChoriaAuth) setClaimsBasedServerPermissions(user *server.User, claims *tokens.ServerClaims, log *logrus.Entry) { 1099 if len(claims.Collectives) == 0 { 1100 log.Warnf("No collectives in server token, denying access") 1101 a.setDenyServersPermissions(user) 1102 return 1103 } 1104 1105 user.Permissions.Subscribe = &server.SubjectPermission{} 1106 user.Permissions.Publish = &server.SubjectPermission{ 1107 Allow: []string{ 1108 "choria.lifecycle.>", 1109 "choria.machine.transition", 1110 "choria.machine.watcher.>", 1111 }, 1112 } 1113 1114 user.Permissions.Publish.Allow = append(user.Permissions.Publish.Allow, claims.AdditionalPublishSubjects...) 1115 1116 for _, c := range claims.Collectives { 1117 user.Permissions.Publish.Allow = append(user.Permissions.Publish.Allow, 1118 fmt.Sprintf("%s.reply.>", c), 1119 fmt.Sprintf("%s.broadcast.agent.registration", c), 1120 fmt.Sprintf("choria.federation.%s.collective", c), 1121 ) 1122 1123 user.Permissions.Subscribe.Allow = append(user.Permissions.Subscribe.Allow, 1124 fmt.Sprintf("%s.broadcast.agent.>", c), 1125 fmt.Sprintf("%s.node.%s", c, claims.ChoriaIdentity), 1126 fmt.Sprintf("%s.reply.%x.>", c, md5.Sum([]byte(claims.ChoriaIdentity))), 1127 ) 1128 1129 if claims.Permissions != nil { 1130 if claims.Permissions.ServiceHost { 1131 user.Permissions.Subscribe.Allow = append(user.Permissions.Subscribe.Allow, 1132 fmt.Sprintf("%s.broadcast.service.>", c), 1133 ) 1134 } 1135 1136 if claims.Permissions.Submission { 1137 user.Permissions.Publish.Allow = append(user.Permissions.Publish.Allow, 1138 fmt.Sprintf("%s.submission.in.>", c), 1139 ) 1140 } 1141 1142 if claims.Permissions.Governor && claims.Permissions.Streams { 1143 user.Permissions.Publish.Allow = append(user.Permissions.Publish.Allow, 1144 fmt.Sprintf("%s.governor.*", c), 1145 ) 1146 } 1147 } 1148 } 1149 1150 if claims.Permissions != nil && claims.Permissions.Streams { 1151 prefix := "$JS.API" 1152 if claims.OrganizationUnit != "choria" { 1153 prefix = "choria.streams" 1154 } 1155 1156 user.Permissions.Publish.Allow = append(user.Permissions.Publish.Allow, 1157 fmt.Sprintf("%s.STREAM.INFO.*", prefix), 1158 fmt.Sprintf("%s.STREAM.MSG.GET.*", prefix), 1159 fmt.Sprintf("%s.STREAM.MSG.DELETE.*", prefix), 1160 fmt.Sprintf("%s.DIRECT.GET.*", prefix), 1161 fmt.Sprintf("%s.DIRECT.GET.*.>", prefix), 1162 fmt.Sprintf("%s.CONSUMER.CREATE.*", prefix), 1163 fmt.Sprintf("%s.CONSUMER.CREATE.*.>", prefix), 1164 fmt.Sprintf("%s.CONSUMER.DURABLE.CREATE.*.*", prefix), 1165 fmt.Sprintf("%s.CONSUMER.INFO.*.*", prefix), 1166 fmt.Sprintf("%s.CONSUMER.MSG.NEXT.*.*", prefix), 1167 "$JS.ACK.>", 1168 "$JS.FC.>", 1169 ) 1170 } 1171 } 1172 1173 func (a *ChoriaAuth) setDefaultServerPermissions(user *server.User) { 1174 user.Permissions.Subscribe = &server.SubjectPermission{ 1175 Deny: []string{ 1176 "*.reply.>", 1177 "choria.federation.>", 1178 "choria.lifecycle.>", 1179 }, 1180 } 1181 1182 user.Permissions.Publish = &server.SubjectPermission{ 1183 Allow: allSubjects, 1184 1185 Deny: []string{ 1186 "*.broadcast.agent.>", 1187 "*.broadcast.service.>", 1188 "*.node.>", 1189 "choria.federation.*.federation", 1190 }, 1191 } 1192 } 1193 1194 func (a *ChoriaAuth) setPubSubPermissions(user *server.User) { 1195 user.Permissions.Publish = &server.SubjectPermission{ 1196 Allow: allSubjects, 1197 Deny: []string{ 1198 "*.broadcast.>", 1199 "*.node.>", 1200 "*.reply.>", 1201 "choria.federation.>", 1202 "choria.lifecycle.>", 1203 "choria.machine.>", 1204 }, 1205 } 1206 1207 user.Permissions.Subscribe = &server.SubjectPermission{ 1208 Allow: allSubjects, 1209 Deny: []string{ 1210 "*.broadcast.>", 1211 "*.node.>", 1212 "*.reply.>", 1213 "choria.federation.>", 1214 "choria.lifecycle.>", 1215 "choria.machine.>", 1216 }, 1217 } 1218 } 1219 1220 func (a *ChoriaAuth) setServerPermissions(user *server.User, claims *tokens.ServerClaims, log *logrus.Entry) { 1221 switch { 1222 case a.denyServers: 1223 log.Debugf("Setting server permissions, denying servers") 1224 a.setDenyServersPermissions(user) 1225 1226 case claims != nil: 1227 log.Debugf("Setting server permissions based on token claims") 1228 a.setClaimsBasedServerPermissions(user, claims, log) 1229 1230 default: 1231 log.Debugf("Setting default server permissions") 1232 a.setDefaultServerPermissions(user) 1233 } 1234 } 1235 1236 func (a *ChoriaAuth) remoteInClientAllowList(remote net.Addr) bool { 1237 if len(a.clientAllowList) == 0 { 1238 return true 1239 } 1240 1241 if remote == nil { 1242 return false 1243 } 1244 1245 host, _, err := net.SplitHostPort(remote.String()) 1246 if err != nil { 1247 a.log.Warnf("Could not extract host from remote, not allowing access to client targets: '%s': %s", remote.String(), err) 1248 1249 return false 1250 } 1251 1252 for _, allowed := range a.clientAllowList { 1253 if host == allowed { 1254 return true 1255 } 1256 1257 if strings.Contains(allowed, "/") { 1258 _, ipnet, err := net.ParseCIDR(allowed) 1259 if err != nil { 1260 a.log.Warnf("Could not parse %s as a cidr: %s", allowed, err) 1261 continue 1262 } 1263 1264 if ipnet.Contains(net.ParseIP(host)) { 1265 return true 1266 } 1267 } 1268 } 1269 1270 return false 1271 } 1272 1273 func (a *ChoriaAuth) isProvisionUser(c server.ClientAuthentication) bool { 1274 opts := c.GetOpts() 1275 return opts.Username == provisioningUser 1276 } 1277 1278 func (a *ChoriaAuth) isSystemUser(c server.ClientAuthentication) bool { 1279 if a.systemUser == "" { 1280 return false 1281 } 1282 1283 opts := c.GetOpts() 1284 return opts.Username == a.systemUser 1285 } 1286 1287 func (a *ChoriaAuth) createUser(c server.ClientAuthentication) *server.User { 1288 opts := c.GetOpts() 1289 1290 acct := a.choriaAccount 1291 1292 return &server.User{ 1293 Username: opts.Username, 1294 Password: opts.Password, 1295 Account: acct, 1296 Permissions: &server.Permissions{}, 1297 } 1298 }