Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ROX-11640: RHSSO dynamic clients rotation API #1236

Merged
merged 11 commits into from
Sep 13, 2023

Conversation

ivan-degtiarenko
Copy link
Contributor

@ivan-degtiarenko ivan-degtiarenko commented Sep 4, 2023

Description

This PR creates an admin API that:

  • creates a new client/secret pair via the dynamic client sso.r.c API.
  • delete the previous dynamic client.
  • updates the client/secret pair in fleet manager DB.

In case of failure to either use new client or delete the previous one, client ID is logged that allows for ACSCS engineer to manually delete stale client.
In case dynamic clients are not configured, 404 status code is returned.

The dynamic clients API client is initialized once, however, it might not be initialized properly if dynamic clients are not configured. Whether dynamic clients are configured is checked on every request.

Checklist (Definition of Done)

  • Unit and integration tests added
  • Added test description under Test manual
  • Documentation added if necessary (i.e. changes to dev setup, test execution, ...)
  • CI and all relevant tests are passing
  • Add the ticket number to the PR title if available, i.e. ROX-12345: ...
  • Discussed security and business related topics privately. Will move any security and business related topics that arise to private communication channel.
  • Add secret to app-interface Vault or Secrets Manager if necessary
  • RDS changes were e2e tested manually
  • Check AWS limits are reasonable for changes provisioning new resources

Test manual

TODO: Add manual testing efforts

(You need to set up SSO_CLIENT_ID_DEFAULT and SSO_CLIENT_SECRET_DEFAULT, as well as specify --central-idp-client-id as empty string)

  1. make deploy/bootstrap
  2. make deploy/dev
  3. Create central
  4. Look into cloud-service-sensible-declarative-configs secret and see client ID and secret values
  5. Call /rotate-secrets endpoint
  6. See that client ID and secret have changed within cloud-service-sensible-declarative-configs

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Sep 4, 2023

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 11:15 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 11:15 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 11:15 — with GitHub Actions Inactive
@openshift-ci openshift-ci bot added the approved label Sep 4, 2023
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 14:42 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 14:42 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 14:42 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 15:54 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 15:54 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 4, 2023 15:54 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 7, 2023 22:41 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 7, 2023 22:41 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 7, 2023 22:41 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 8, 2023 10:55 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 8, 2023 10:55 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 8, 2023 10:55 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko changed the title WIP: RHSSO dynamic clients rotation API ROX-11640: RHSSO dynamic clients rotation API Sep 8, 2023
@ivan-degtiarenko ivan-degtiarenko marked this pull request as ready for review September 8, 2023 11:04
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 8, 2023 11:04 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 8, 2023 11:04 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 8, 2023 11:04 — with GitHub Actions Inactive
@dhaus67 dhaus67 self-requested a review September 8, 2023 12:29
Copy link
Contributor

@johannes94 johannes94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just suggested some naming/method changes.

Please also update the API documentation(./openapi/fleet-manager-private-admin.yaml).

@@ -415,6 +417,22 @@ func (h adminCentralHandler) GetCentralDefaultVersion(w http.ResponseWriter, r *
handlers.Handle(w, r, cfg, http.StatusOK)
}

func (h adminCentralHandler) RotateSecrets(w http.ResponseWriter, r *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this handler could be ambiguous. We also store other secrets within a central request of FM DB which are not rotated by this operation. I'd suggest to make it more specific like you did in the service, something like `RotateCentralRHSSOClient'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original idea was that we might want to extend this endpoint with more secret rotation in the future, however, there's no indication it will ever be the case. I'll rename the handler 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to rename, see comment below.

@@ -256,6 +256,9 @@ func (s *options) buildAPIBaseRouter(mainRouter *mux.Router, basePath string, op
adminCentralsRouter.HandleFunc("/{id}", adminCentralHandler.Update).
Name(logger.NewLogEvent("admin-update-central", "[admin] update central by id").ToString()).
Methods(http.MethodPatch)
adminCentralsRouter.HandleFunc("/{id}/rotate-secrets", adminCentralHandler.RotateSecrets).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment about the handler name, the route should also reflect that.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think we have two ways to go here:

  • Either keep this one "generic" and leave it open for extending it.
  • Create "RPC-style" API which has options like rotate/dynamic-client, rotate/dns or whatever else we might want to rotate for an existing instance in the future.

Having the extensibility in mind, I wouldn't mind keeping it "unspecific" and have the option to extend it further down the road.

Copy link
Contributor

@johannes94 johannes94 Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Lets keep it generic. I already have another use case in mind for this endpoint. Rotating the backed up namespace secrets if we need to do CA rotation.

@@ -256,6 +256,9 @@ func (s *options) buildAPIBaseRouter(mainRouter *mux.Router, basePath string, op
adminCentralsRouter.HandleFunc("/{id}", adminCentralHandler.Update).
Name(logger.NewLogEvent("admin-update-central", "[admin] update central by id").ToString()).
Methods(http.MethodPatch)
adminCentralsRouter.HandleFunc("/{id}/rotate-secrets", adminCentralHandler.RotateSecrets).
Name(logger.NewLogEvent("admin-rotate-central-secrets", "[admin] rotate central secrets by id").ToString()).
Methods(http.MethodPatch)
Copy link
Contributor

@johannes94 johannes94 Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer http.MethodPost at this point. For me PATCH indicates that I partially update the resource with the resource body I send. Which doesn't match to what the endpoint is doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think POST does not apply here because POST indicates the creation of a new resource, while PATCH indicates partial modification of an existing resource.

I agree with you that having PATCH without a body is weird as well(although If I read correctly does not go against RFC. IMHO out of all 3 potential methods(POST, PUT, PATCH) I think PATCH comes the closest to the standard.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we're doing here isn't really REST since it's not necessarily related to CRUD (you don't really create a resource, or update it per-se, but rather trigger an action).

Looking at the overall industry, POST seems to be the common standard to use when triggering actions like revoking things, let's use it instead of PATCH.

Both are also open for extending it, like we said in case we want to rotate more secrets than just the sso.r.c dynamic client.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POST it is

internal/dinosaur/pkg/handlers/admin_dinosaur.go Outdated Show resolved Hide resolved
internal/dinosaur/pkg/handlers/admin_dinosaur.go Outdated Show resolved Hide resolved
internal/dinosaur/pkg/rhsso/augment.go Outdated Show resolved Hide resolved
@@ -256,6 +256,9 @@ func (s *options) buildAPIBaseRouter(mainRouter *mux.Router, basePath string, op
adminCentralsRouter.HandleFunc("/{id}", adminCentralHandler.Update).
Name(logger.NewLogEvent("admin-update-central", "[admin] update central by id").ToString()).
Methods(http.MethodPatch)
adminCentralsRouter.HandleFunc("/{id}/rotate-secrets", adminCentralHandler.RotateSecrets).
Name(logger.NewLogEvent("admin-rotate-central-secrets", "[admin] rotate central secrets by id").ToString()).
Methods(http.MethodPatch)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we're doing here isn't really REST since it's not necessarily related to CRUD (you don't really create a resource, or update it per-se, but rather trigger an action).

Looking at the overall industry, POST seems to be the common standard to use when triggering actions like revoking things, let's use it instead of PATCH.

Both are also open for extending it, like we said in case we want to rotate more secrets than just the sso.r.c dynamic client.

@@ -256,6 +256,9 @@ func (s *options) buildAPIBaseRouter(mainRouter *mux.Router, basePath string, op
adminCentralsRouter.HandleFunc("/{id}", adminCentralHandler.Update).
Name(logger.NewLogEvent("admin-update-central", "[admin] update central by id").ToString()).
Methods(http.MethodPatch)
adminCentralsRouter.HandleFunc("/{id}/rotate-secrets", adminCentralHandler.RotateSecrets).
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think we have two ways to go here:

  • Either keep this one "generic" and leave it open for extending it.
  • Create "RPC-style" API which has options like rotate/dynamic-client, rotate/dns or whatever else we might want to rotate for an existing instance in the future.

Having the extensibility in mind, I wouldn't mind keeping it "unspecific" and have the option to extend it further down the road.

internal/dinosaur/pkg/services/dinosaur.go Show resolved Hide resolved
Comment on lines 132 to 133
ErrorClientRotationNotConfigured ServiceErrorCode = 116
ErrorClientRotationNotConfiguredReason string = "RHSSO client rotation is not configured"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really ClientRotationNotConfigured or rather DynamicClientNotConfigured?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible for client rotation not to be configured but dynamic clients to be configured, because in code we give preference to static configuration if it's configured

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call it DynamicClientNotUsed then? My point is we don't have a configuration for client rotation, and if anyone other than the two of us reads the error message they might be confused as to what is going on / why it isn't working; and which configuration option to set 😅

internal/dinosaur/pkg/services/dinosaur.go Outdated Show resolved Hide resolved
internal/dinosaur/pkg/services/dinosaur.go Outdated Show resolved Hide resolved
internal/dinosaur/pkg/services/dinosaur.go Outdated Show resolved Hide resolved
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 12, 2023 11:21 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 12, 2023 12:32 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 12, 2023 12:32 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 12, 2023 12:32 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 12, 2023 13:00 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 12, 2023 13:00 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 12, 2023 13:00 — with GitHub Actions Inactive
internal/dinosaur/pkg/services/dinosaur.go Outdated Show resolved Hide resolved
@@ -2,12 +2,10 @@ package dinosaurmgrs

import (
"context"
"fmt"
"github.com/stackrox/acs-fleet-manager/internal/dinosaur/pkg/rhsso"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's format this properly and put it below to the non-standard packages.

Copy link
Contributor

@johannes94 johannes94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Sep 13, 2023

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dhaus67, ivan-degtiarenko, johannes94

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [dhaus67,ivan-degtiarenko,johannes94]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot removed the lgtm label Sep 13, 2023
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Sep 13, 2023

New changes are detected. LGTM label has been removed.

@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 13, 2023 16:41 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 13, 2023 16:41 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 13, 2023 16:41 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 13, 2023 16:46 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 13, 2023 16:46 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko temporarily deployed to development September 13, 2023 16:46 — with GitHub Actions Inactive
@ivan-degtiarenko ivan-degtiarenko merged commit 8220021 into main Sep 13, 2023
@ivan-degtiarenko ivan-degtiarenko deleted the ivan/rhsso-client-rotation-api branch September 13, 2023 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants