Skip to content

Add support for custom group claims#133

Merged
EthanHeilman merged 5 commits into
openpubkey:mainfrom
mvanderlee:issue-123
Sep 21, 2025
Merged

Add support for custom group claims#133
EthanHeilman merged 5 commits into
openpubkey:mainfrom
mvanderlee:issue-123

Conversation

@mvanderlee
Copy link
Copy Markdown
Contributor

@mvanderlee mvanderlee commented Apr 15, 2025

This adds the ability set policy based on the value of any claim in the ID Token.

For instance:

dev oidc:someClaim:developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0

Would allow anyone with an ID Token whose claim "someClaim" had the value "developer" to login as the linux user dev (assuming the ID Token is valid for the configured OP.

Fixes #123

I don't have much Go experience, but I have tested this on EC2 with Auth0 as IDP using a URL as group name.

@EthanHeilman
Copy link
Copy Markdown
Member

Thanks for putting this together. I fixed up some the linter errors. It is on my list of PRs to review, but I might not get to it for a few days.

@EthanHeilman
Copy link
Copy Markdown
Member

@mvanderlee Lets wait on this until we have quotes and escaped spaces in #120

Then implementing this using CEL

@EthanHeilman
Copy link
Copy Markdown
Member

@mvanderlee The prereq for this PR #158 which added escaping has been merged. No need to wait on escaping anymore

@mvanderlee
Copy link
Copy Markdown
Contributor Author

@EthanHeilman What is needed for this PR to be merged?
I don't really understand what #158 has added.

@EthanHeilman
Copy link
Copy Markdown
Member

EthanHeilman commented Sep 3, 2025

@mvanderlee

I don't really understand what #158 has added.

Imagine you have a custom group claim like IT admins.

operator oidc:opkssh_groups:IT admins https://accounts.google.com

This would break policy since the policy file is space delimited. It would see four rows

operator 
oidc:opkssh_groups:IT
admins 
https://accounts.google.com

Now we can use quotes to include groups with spaces.

operator "oidc:opkssh_groups:IT admins" https://accounts.google.com

It will see three rows

operator 
"idc:opkssh_groups:IT admins"
https://accounts.google.com

What is needed for this PR to be merged?

  1. Unit tests

  2. Documentation

Wouldn't this allow using any ID Token as a policy rule? If so I see that a good thing and we should frame it that way in the documentation and code. Rather than potentialGroupClaims, it could be potentialClaims.

Comment thread README.md Outdated

# Group identifier
dev oidc:groups:developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
dev oidc|groups|developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why the switch from : to |?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The switch was to allow URLs as group identifiers.
i.e.: ec2-user oidc|https://acme.com/groups|PROD_SSH https://acme.com/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we escape quote here instead? We are already stuck with : and putting pipes (|) would require quotes anyways to shell escape them

ec2-user oidc:"https://acme.com/groups":"PROD_SSH" https://acme.com/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sorry I haven't looked at go since April. The readme change to : is incorrect and should be reverted.
The currently supported oidc:groups prefix continues to work with :.
If we don't find a match, but it does start with oidc then we check for a piped split with custom group attribute.

Example, all of these work in the current code.

dev oidc:groups:developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
dev oidc|groups|developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0

dev oidc|https://acme.com/groups|developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0

But I'm checking on quoting now.

@mvanderlee mvanderlee force-pushed the issue-123 branch 3 times, most recently from 34ceaff to 23ce6ba Compare September 5, 2025 21:29
@mvanderlee
Copy link
Copy Markdown
Contributor Author

@EthanHeilman ready for review. I've added escaping, documentation, and testing.

Example

dev oidc:"https://acme.com/groups":developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0

@EthanHeilman
Copy link
Copy Markdown
Member

@mvanderlee Thanks for all your work on this. I would have time to take a look at it until Thursday as I really want to test it out and play around with the code. Policy changes are always tricky in unexpected ways

Copy link
Copy Markdown
Member

@EthanHeilman EthanHeilman left a comment

Choose a reason for hiding this comment

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

LGTM, I made some minor changes

@EthanHeilman EthanHeilman merged commit bea5703 into openpubkey:main Sep 21, 2025
16 checks passed
@EthanHeilman
Copy link
Copy Markdown
Member

Thanks for putting this PR together. Sorry it took me so long to review and merge. Normally I am much faster about reviews

@EthanHeilman
Copy link
Copy Markdown
Member

Tested this by letting anyone with the name Ethan log into my vm. =)

cat /etc/opk/auth_id
ethan oidc:given_name:Ethan https://accounts.google.com

@mvanderlee
Copy link
Copy Markdown
Contributor Author

Nice! I've been using it as well, and it work well! We do need to escape the quotes.

ec2-user oidc:\\\"https://acme.com/groups\\\":prod https://adme.com/

@EthanHeilman
Copy link
Copy Markdown
Member

Do you escape the quotes in opkssh add or are you editing the file directly?

@mvanderlee
Copy link
Copy Markdown
Contributor Author

We edit the file directly through our IAC via Terraform + Ansible.

@EthanHeilman
Copy link
Copy Markdown
Member

Does a single escape not work?

ec2-useroidc:\"https://acme.com/groups\":prod https://adme.com

Is escaping the escapes in example needed?

ec2-user oidc:\\\"https://acme.com/groups\\\":prod https://adme.com

If so, we have a bug because opkssh add creates ec2-useroidc:"https://acme.com/groups\":prod https://adme.com` not ec2-user oidc:\\\"https://acme.com/groups\\\":prod https://adme.com

@mvanderlee
Copy link
Copy Markdown
Contributor Author

Yes because of the shellquote added in PR #158

@EthanHeilman
Copy link
Copy Markdown
Member

@mvanderlee

I wrote the following test to double check

var pathToAuthFile = "path/to/auth_id2.test"

func TestPolicyUrlClaim(t *testing.T) {
	loader := &policy.PolicyLoader{
		FileLoader: files.FileLoader{
			Fs:           afero.NewOsFs(),
			RequiredPerm: fs.FileMode(0666),
		},
	}

	p, err := loader.LoadPolicyAtPath(pathToAuthFile)
	require.NoError(t, err)
	require.Len(t, p.Users, 1)

	providerOpts := providers.DefaultMockProviderOpts()
	op, _, idTokenTemplate, err := providers.NewMockProvider(providerOpts)
	require.NoError(t, err)
	idTokenTemplate.ExtraClaims = map[string]any{"email": "arthur.aardvark@example.com",
		"https://acme.com/groups": []string{"prod"}}

	opkClient, err := client.New(op)
	require.NoError(t, err)
	pkt, err := opkClient.Auth(context.Background())
	require.NoError(t, err)

	payloadB64 := bytes.Split(pkt.OpToken, []byte{'.'})[1]
	require.NoError(t, err)

	pktJson, err := util.Base64DecodeForJWT(payloadB64)
	require.NoError(t, err)

	var claims map[string]any
	err = json.Unmarshal(pktJson, &claims)
	require.NoError(t, err)

	policyEnforcer := &policy.Enforcer{
		PolicyLoader: &MockPolicyLoader{Policy: p},
	}

	err = policyEnforcer.CheckPolicy("test_user", pkt, "", "example-base64Cert", "ssh-rsa", policy.DenyList{})
	require.NoError(t, err)
}

The test passes for:

test_user oidc:\"https://acme.com/groups\":prod https://accounts.example.com

the test fails for:

test_user oidc:\\\"https://acme.com/groups\\\:prod https://accounts.example.com

So I don't think there is a bug. Are you using test_user oidc:\\\"https://acme.com/groups\\\:prod https://accounts.example.com in your actual auth_id file and it is working for you?

renovate Bot added a commit to sdwilsh/ansible-playbooks that referenced this pull request Jan 5, 2026
##### [\`v0.11.0\`](https://github.com/openpubkey/opkssh/releases/tag/v0.11.0)

##### 🚀 Features

- Add support for custom group claims [@mvanderlee](https://github.com/mvanderlee) ([#133](openpubkey/opkssh#133))
- feat: Flag to print SSH cert and private key rather than FS [@EthanHeilman](https://github.com/EthanHeilman) ([#437](openpubkey/opkssh#437))
- feat: Process extra arguments to the verify command [@justincmoy](https://github.com/justincmoy) ([#436](openpubkey/opkssh#436))
- Add warning message when email claim is missing from ID token @[copilot-swe-agent\[bot\]](https://github.com/apps/copilot-swe-agent) ([#374](openpubkey/opkssh#374))
- \[feat] Add new "inspect" subcommand [@stmcginnis](https://github.com/stmcginnis) ([#349](openpubkey/opkssh#349))
- Add CLI reference documentation [@stmcginnis](https://github.com/stmcginnis) ([#365](openpubkey/opkssh#365))
- Include signature JSON in `inspect` output [@stmcginnis](https://github.com/stmcginnis) ([#358](openpubkey/opkssh#358))
- - docs: Add Amazon Cognito as tested provider [@Foorack](https://github.com/Foorack) ([#414](openpubkey/opkssh#414))
- docs: Add documentation for opkssh and sssd integration [@vigneshmanick](https://github.com/vigneshmanick) ([#409](openpubkey/opkssh#409))
- Added SELinux support for sudo logging [@descensus](https://github.com/descensus) ([#376](openpubkey/opkssh#376))
- Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#368](openpubkey/opkssh#368))

##### 🐛 Bug Fixes

- Fix race condition in ReadHome [@gcorrall](https://github.com/gcorrall) ([#391](openpubkey/opkssh#391))
- \[fix] Use lowercase for positional argument placeholders [@t38miwa](https://github.com/t38miwa) ([#361](openpubkey/opkssh#361))
- fix typo in commands/verify.go [@DevRockstarZ](https://github.com/DevRockstarZ) ([#336](openpubkey/opkssh#336))
- Doc: fix small errors in policy plugin doc [@PotatoesMaster](https://github.com/PotatoesMaster) ([#344](openpubkey/opkssh#344))
- Correct macOS name [@stmcginnis](https://github.com/stmcginnis) ([#341](openpubkey/opkssh#341))

##### 🧰 Maintenance

- chore: document upstream nix usage & remove nix flake [@datosh](https://github.com/datosh) ([#383](openpubkey/opkssh#383))
- Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#438](openpubkey/opkssh#438))
- Stop hash pinning docker images [@EthanHeilman](https://github.com/EthanHeilman) ([#421](openpubkey/opkssh#421))
- \[fix] Fix ssh version integration test [@EthanHeilman](https://github.com/EthanHeilman) ([#362](openpubkey/opkssh#362))
- Fix integration tests failing due to pacman keys [@EthanHeilman](https://github.com/EthanHeilman) ([#432](openpubkey/opkssh#432))
- fix(deps): Update docker/setup-buildx-action action to v3.12.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#426](openpubkey/opkssh#426))
- fix(deps): Update zizmorcore/zizmor-action action to v0.3.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#413](openpubkey/opkssh#413))
- fix(deps): Update peter-evans/create-pull-request action to v8 @[renovate\[bot\]](https://github.com/apps/renovate) ([#418](openpubkey/opkssh#418))
- fix(deps): Update zizmorcore/zizmor-action action to v0.2.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#335](openpubkey/opkssh#335))
- fix(deps): Update peter-evans/create-pull-request action to v7.0.9 @[renovate\[bot\]](https://github.com/apps/renovate) ([#407](openpubkey/opkssh#407))
sdwilsh pushed a commit to sdwilsh/ansible-playbooks that referenced this pull request Jan 13, 2026
##### [\`v0.11.0\`](https://github.com/openpubkey/opkssh/releases/tag/v0.11.0)

##### 🚀 Features

- Add support for custom group claims [@mvanderlee](https://github.com/mvanderlee) ([#133](openpubkey/opkssh#133))
- feat: Flag to print SSH cert and private key rather than FS [@EthanHeilman](https://github.com/EthanHeilman) ([#437](openpubkey/opkssh#437))
- feat: Process extra arguments to the verify command [@justincmoy](https://github.com/justincmoy) ([#436](openpubkey/opkssh#436))
- Add warning message when email claim is missing from ID token @[copilot-swe-agent\[bot\]](https://github.com/apps/copilot-swe-agent) ([#374](openpubkey/opkssh#374))
- \[feat] Add new "inspect" subcommand [@stmcginnis](https://github.com/stmcginnis) ([#349](openpubkey/opkssh#349))
- Add CLI reference documentation [@stmcginnis](https://github.com/stmcginnis) ([#365](openpubkey/opkssh#365))
- Include signature JSON in `inspect` output [@stmcginnis](https://github.com/stmcginnis) ([#358](openpubkey/opkssh#358))
- - docs: Add Amazon Cognito as tested provider [@Foorack](https://github.com/Foorack) ([#414](openpubkey/opkssh#414))
- docs: Add documentation for opkssh and sssd integration [@vigneshmanick](https://github.com/vigneshmanick) ([#409](openpubkey/opkssh#409))
- Added SELinux support for sudo logging [@descensus](https://github.com/descensus) ([#376](openpubkey/opkssh#376))
- Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#368](openpubkey/opkssh#368))

##### 🐛 Bug Fixes

- Fix race condition in ReadHome [@gcorrall](https://github.com/gcorrall) ([#391](openpubkey/opkssh#391))
- \[fix] Use lowercase for positional argument placeholders [@t38miwa](https://github.com/t38miwa) ([#361](openpubkey/opkssh#361))
- fix typo in commands/verify.go [@DevRockstarZ](https://github.com/DevRockstarZ) ([#336](openpubkey/opkssh#336))
- Doc: fix small errors in policy plugin doc [@PotatoesMaster](https://github.com/PotatoesMaster) ([#344](openpubkey/opkssh#344))
- Correct macOS name [@stmcginnis](https://github.com/stmcginnis) ([#341](openpubkey/opkssh#341))

##### 🧰 Maintenance

- chore: document upstream nix usage & remove nix flake [@datosh](https://github.com/datosh) ([#383](openpubkey/opkssh#383))
- Update CLI documentation @[github-actions\[bot\]](https://github.com/apps/github-actions) ([#438](openpubkey/opkssh#438))
- Stop hash pinning docker images [@EthanHeilman](https://github.com/EthanHeilman) ([#421](openpubkey/opkssh#421))
- \[fix] Fix ssh version integration test [@EthanHeilman](https://github.com/EthanHeilman) ([#362](openpubkey/opkssh#362))
- Fix integration tests failing due to pacman keys [@EthanHeilman](https://github.com/EthanHeilman) ([#432](openpubkey/opkssh#432))
- fix(deps): Update docker/setup-buildx-action action to v3.12.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#426](openpubkey/opkssh#426))
- fix(deps): Update zizmorcore/zizmor-action action to v0.3.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#413](openpubkey/opkssh#413))
- fix(deps): Update peter-evans/create-pull-request action to v8 @[renovate\[bot\]](https://github.com/apps/renovate) ([#418](openpubkey/opkssh#418))
- fix(deps): Update zizmorcore/zizmor-action action to v0.2.0 @[renovate\[bot\]](https://github.com/apps/renovate) ([#335](openpubkey/opkssh#335))
- fix(deps): Update peter-evans/create-pull-request action to v7.0.9 @[renovate\[bot\]](https://github.com/apps/renovate) ([#407](openpubkey/opkssh#407))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFE: Groups claim based authorization - customize groups key

2 participants