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

Auth: Extended JWT client for OBO and Service Authentication #83814

Merged
merged 44 commits into from Apr 2, 2024

Conversation

Jguer
Copy link
Contributor

@Jguer Jguer commented Mar 4, 2024

Pair PR: https://github.com/grafana/auth/pull/583

What is this feature?

Extended JWT client allows On Behalf Of (impersonation) and Service authentication via an auth api access token.

  • Authenticate the Access policy as itself
  • Scoped by the access policy’s realm, scopes and attributes (Permissions and DelegatedPermissions) and request caller
  • Short term expiration (Expiration measured in minutes)
  • Can only be created using the API
  • Designed for internal service use
  • Should not be shared with users
  • Is a JWT (can be locally validated)

Accessing Grafana as the service

Example use case: Authz proxy needs to search permissions for every user in a dedicated privileged endpoint

curl -k  'http://localhost:3000/api/user' -H 'X-Access-Token: eyJ…'

X-Access-Token should be the Cloud Access Policy Access Token
Will return the user as the access policy. The namespaced ID in grafana will be access-policy:xxxx and it will not be persisted in the database. This ID cannot own things in grafana.
Permissions will be derived from the roles present in the permissions claim of the access token.

Accessing Grafana as a user

Example use case: plugin needs to know which folders a user can view

curl -k  'http://localhost:3000/api/user' -H 'X-Access-Token: eyJ…' -H 'X-Grafana-Id: eyJ…'

By providing both Access Token and Grafana User ID Token it is possible to authenticate as the user. The namespaced ID in Grafana will be the user’s ID.
The permissions for this call will be the intersection between the user’s stored permissions and the allowed actions specified by “delegatedPermissions”.

Why do we need this feature?

Impersonation access missing for background tasks and proxy

Who is this feature for?

Backend platform and cloud plugin developers

Which issue(s) does this PR fix?:

Fixes #

Special notes for your reviewer:

Please check that:

  • It works as expected from a user's perspective.
  • If this is a pre-GA feature, it is behind a feature toggle.
  • The docs are updated, and if this is a notable improvement, it's added to our What's New doc.

@Jguer Jguer self-assigned this Mar 4, 2024
@grafana-delivery-bot grafana-delivery-bot bot added this to the 11.0.x milestone Mar 4, 2024
@grafanabot
Copy link
Contributor

❌ Failed to run Playwright plugin e2e tests.

Click here to browse the Playwright report and trace viewer.
For information on how to run Playwright tests locally, refer to the Developer guide.

@Jguer Jguer marked this pull request as ready for review March 6, 2024 09:34
@Jguer Jguer requested review from a team as code owners March 6, 2024 09:34
@Jguer Jguer requested review from zserge, mildwonkey and suntala and removed request for a team March 6, 2024 09:34
@Jguer Jguer added no-backport Skip backport of PR no-changelog Skip including change in changelog/release notes labels Mar 6, 2024
@Jguer Jguer requested a review from a team as a code owner April 2, 2024 08:08
@Jguer Jguer requested a review from a team as a code owner April 2, 2024 08:39
@Jguer Jguer requested review from wbrowne, marefr and xnyo and removed request for a team April 2, 2024 08:39
@@ -205,15 +206,18 @@ func (u *SignedInUser) GetID() string {
return namespacedID(identity.NamespaceRenderService, 0)
}

// backwards compatibility
return namespacedID(identity.NamespaceUser, u.UserID)
return u.NamespacedID
}

// GetNamespacedID returns the namespace and ID of the active entity
// The namespace is one of the constants defined in pkg/services/auth/identity
func (u *SignedInUser) GetNamespacedID() (string, string) {
parts := strings.Split(u.GetID(), ":")
// Safety: GetID always returns a ':' separated string
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove this part if this is no longer true

Comment on lines +65 to +66
// Grafana roles
Permissions []string `json:"permissions"`
Copy link
Contributor

Choose a reason for hiding this comment

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

How come we are using RBAC roles here and not just plain permissions as the name suggest?

Comment on lines +97 to +99
if !strings.HasPrefix(accessTokenClaims.Subject, fmt.Sprintf("%s:", authn.NamespaceAccessPolicy)) {
s.log.Error("Invalid subject", "subject", accessTokenClaims.Subject)
return nil, errJWTInvalid.Errorf("Failed to parse sub: %s", "invalid subject format")
Copy link
Contributor

Choose a reason for hiding this comment

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

we should move this check to Authenticate and remove from authenticateAsUser and authenticateAsService

"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/tests/testsuite"
"github.com/stretchr/testify/require"
Copy link
Contributor

Choose a reason for hiding this comment

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

you can remove this change

Comment on lines +8 to +9
"github.com/stretchr/testify/require"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
"github.com/stretchr/testify/require"

@Jguer
Copy link
Contributor Author

Jguer commented Apr 2, 2024

/deploy-hg

@Jguer
Copy link
Contributor Author

Jguer commented Apr 2, 2024

/deploy-to-hg

@ephemeral-instances-bot
Copy link

  • Preparing your instance. A comment containing your instance's url will be added to this PR when the instance is ready.
  • Your instance will be ready in ~10 minutes.
  • Check the GitHub actions tab to follow the workflow progress
  • Slack channel: #proj-ephemeral-hg-instances
  • Building instance with jguer/repurpose-ext-jwt-client oss branch and main enterprise branch. How to choose a branch

@ephemeral-instances-bot
Copy link

Copy link
Contributor

@andresmgot andresmgot left a comment

Choose a reason for hiding this comment

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

LGTM from the plugins-platform perspective.

@Jguer
Copy link
Contributor Author

Jguer commented Apr 2, 2024

tested with ephemeral instance to ensure report was still sent.

Merging the current state and we'll continue to iterate (and testing how well it integrates).

@Jguer
Copy link
Contributor Author

Jguer commented Apr 2, 2024

May cause some services to receive unexpected namespacedIDs if the service is not parsing accepted namespaces (ex: "rendering-service:0" instead of "user:0")

@Jguer Jguer merged commit 5340a6e into main Apr 2, 2024
19 checks passed
@Jguer Jguer deleted the jguer/repurpose-ext-jwt-client branch April 2, 2024 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/backend area/frontend no-backport Skip backport of PR no-changelog Skip including change in changelog/release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants