replaceRemoteAdminServer replaces the running remote admin server according to the relevant configuration in cfg. It stops any previous remote admin server and only starts a new one if configured.
(ctx Context, cfg *Config)
| 508 | // according to the relevant configuration in cfg. It stops any previous |
| 509 | // remote admin server and only starts a new one if configured. |
| 510 | func replaceRemoteAdminServer(ctx Context, cfg *Config) error { |
| 511 | if cfg == nil { |
| 512 | return nil |
| 513 | } |
| 514 | |
| 515 | remoteLogger := Log().Named("admin.remote") |
| 516 | |
| 517 | oldAdminServer := remoteAdminServer |
| 518 | defer func() { |
| 519 | if oldAdminServer != nil { |
| 520 | go func(oldAdminServer *http.Server) { |
| 521 | err := stopAdminServer(oldAdminServer) |
| 522 | if err != nil { |
| 523 | Log().Named("admin").Error("stopping current secure admin endpoint", zap.Error(err)) |
| 524 | } |
| 525 | }(oldAdminServer) |
| 526 | } |
| 527 | }() |
| 528 | |
| 529 | if cfg.Admin == nil || cfg.Admin.Remote == nil { |
| 530 | return nil |
| 531 | } |
| 532 | |
| 533 | addr, err := parseAdminListenAddr(cfg.Admin.Remote.Listen, DefaultRemoteAdminListen) |
| 534 | if err != nil { |
| 535 | return err |
| 536 | } |
| 537 | |
| 538 | // make the HTTP handler but disable Host/Origin enforcement |
| 539 | // because we are using TLS authentication instead |
| 540 | handler, err := cfg.Admin.newAdminHandler(addr, true, ctx) |
| 541 | if err != nil { |
| 542 | return err |
| 543 | } |
| 544 | |
| 545 | // create client certificate pool for TLS mutual auth, and extract public keys |
| 546 | // so that we can enforce access controls at the application layer |
| 547 | clientCertPool := x509.NewCertPool() |
| 548 | for i, accessControl := range cfg.Admin.Remote.AccessControl { |
| 549 | for j, certBase64 := range accessControl.PublicKeys { |
| 550 | cert, err := decodeBase64DERCert(certBase64) |
| 551 | if err != nil { |
| 552 | return fmt.Errorf("access control %d public key %d: parsing base64 certificate DER: %v", i, j, err) |
| 553 | } |
| 554 | accessControl.publicKeys = append(accessControl.publicKeys, cert.PublicKey) |
| 555 | clientCertPool.AddCert(cert) |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | // create TLS config that will enforce mutual authentication |
| 560 | if identityCertCache == nil { |
| 561 | return fmt.Errorf("cannot enable remote admin without a certificate cache; configure identity management to initialize a certificate cache") |
| 562 | } |
| 563 | cmCfg := cfg.Admin.Identity.certmagicConfig(remoteLogger, false) |
| 564 | tlsConfig := cmCfg.TLSConfig() |
| 565 | tlsConfig.NextProtos = nil // this server does not solve ACME challenges |
| 566 | tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert |
| 567 | tlsConfig.ClientCAs = clientCertPool |