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

Propagate external traits to leaf clusters #6540

Merged
merged 1 commit into from
Apr 29, 2021
Merged

Propagate external traits to leaf clusters #6540

merged 1 commit into from
Apr 29, 2021

Conversation

r0mant
Copy link
Collaborator

@r0mant r0mant commented Apr 21, 2021

This pull request makes sure that external user traits (usually populated from OIDC/SAML claims/attributes) are propagated to leaf clusters and can be used in leaf role templating. I have extracted this part from the larger AAP headers passthrough work since it felt like this could be a somewhat independent change.

This allows users to have, for example, identical roles in both clusters that grant access based on the user's traits, which is the behavior some customers expect. Example role node labels:

node_labels:
  env: {{external.env}}

Fixes #6389.

@r0mant r0mant requested review from awly and russjones April 21, 2021 19:44
@r0mant r0mant self-assigned this Apr 21, 2021
@r0mant r0mant requested a review from klizhentas as a code owner April 21, 2021 19:44
// behavior, filter out any "internal" traits when applying traits from
// user identity.
for k, v := range u.Identity.Traits {
if !teleport.IsInternalTrait(k) {
Copy link
Contributor

Choose a reason for hiding this comment

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

optional: you could check whether k is already in traits instead of using a helper function
that way you have 1 fewer places to maintain "internal" traits

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good idea, done.

// roles in root and leaf clusters.
func TestTraitsPropagation(t *testing.T) {
log := testlog.FailureOnly(t)
startPort := utils.PortStartingNumber + (5 * AllocatePortsNum) + 1
Copy link
Contributor

Choose a reason for hiding this comment

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

why this formula?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It was needed to avoid conflicts with ports allocated by other tests. It was pretty unfortunate, we would just do it by doing 3*AllocatePortsNum, 4*AllocatePortsNum etc. in different tests until now.

I have refactored this to allocate ports for all integration tests once when they start so individual tests/suites don't need to do that anymore. Hopefully we don't run out of ports, I made it 5000 but I don't think our integration tests actually need that many.

Comment on lines 152 to 165
// Prior to Teleport 6.2 no user traits were passed to remote clusters
// except for those specified above. To preserve backwards compatible
// behavior, filter out any "internal" traits when applying traits from
// user identity.
for k, v := range u.Identity.Traits {
if _, ok := traits[k]; !ok {
traits[k] = v
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Two questions:

  1. I'm not seeing the filtering out of internal traits mentioned in the comment?
  2. When can the second condition be met? Looks like you're just copying the map right? Shouldn't get duplicate keys ever?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@russjones The filtering is the if _, ok := traits[k]; !ok { check - we're basically filtering out any traits which are already present in the traits above which contains only internal ones. In my original implementation I had an explicit function IsInternalTrait that would check if the trait is one of the "logins", "kube groups/users" or "db names/users", but then Andrew pointed out that I can check if the key is already in that traits map, which I did.

When can the second condition be met?

Not sure which condition you mean? We're copying traits from the certificate essentially into the traits map and skipping internal ones to make sure to preserve backwards compatible behavior.

Comment on lines -464 to -496
// extractRolesFromCert extracts roles from certificate metadata extensions.
func extractRolesFromCert(cert *ssh.Certificate) ([]string, error) {
data, ok := cert.Extensions[teleport.CertExtensionTeleportRoles]
if !ok {
// it's ok to not have any roles in the metadata
return nil, nil
}
return services.UnmarshalCertRoles(data)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this was for old style SSH certificates, do you know if we've dropped support for them?

Copy link
Collaborator Author

@r0mant r0mant Apr 28, 2021

Choose a reason for hiding this comment

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

@russjones This logic is still being used - this was just a duplicate function. I've exported extractRolesFromCert and extractTraitsFromCert to use here instead (accounting for the possibility that they may return NotFound in case there are no roles/traits in old-style certs).

@r0mant r0mant force-pushed the roman/traits branch 2 times, most recently from 8164ca7 to 71589ef Compare April 28, 2021 15:26
@r0mant r0mant enabled auto-merge (squash) April 29, 2021 16:28
@r0mant r0mant merged commit 7f01f2d into master Apr 29, 2021
@r0mant r0mant deleted the roman/traits branch April 29, 2021 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Apply trait in leafs as in root
3 participants