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

feat(gcp): enable organization validation #2133

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ericnorris
Copy link

Hey all, I'm submitting a PR to enable validating that a project is a part of a GCP organization, rather than a static list of project IDs. As I mention in the commit message, I tried to strike the right balance between production-ready and proof-of-concept, so feel free to leave as much feedback as possible since I'm open to changing anything.

I'm going to share the first commit message below:


Before this commit, users could specify a hardcoded list of project IDs to restrict access to the GCP provisioner. While this works, it can be both toilsome to the team maintaining the Smallstep installation and unintuitive to the internal infrastructure users that may encounter errors as a result of their project not being added.

This commit is a rough attempt at adding support for validating that a GCP project belongs to a given GCP organization. It does this by using the projects.getAncestry call in the Cloud Resource Manager API. If a token's project claim does not have the given organization ID as its topmost ancestor, the token is rejected. This will require the resourcemanager.projects.get IAM permission on the organization.

The new OrganizationID configuration directive is compatible with the existing ProjectIDs configuration. If ProjectIDs is non-empty, it will take precedence over the OrganizationID and act as it did before, with the minor difference that if OrganizationID is also non-empty, the provisioner will check the project's ancestry before rejecting the token.

There are a couple outstanding questions and tasks after this commit. I tried to strike the right balance between production-ready and proof-of-concept here, so I'm open to any suggestions.

  • Is the authority/provisioner/gcp package the right place for adding this functionality? Is the new struct the right approach?
  • We should add tests for validating the organization ID.
  • How should users configure the authentication for the Cloud Resource Manager client? I expect this would be similar to the Cloud KMS integration.
  • Does Smallstep Professional run in an environment that will be able to authenticate with Google? We would need to either grant permissions to a Smallstep-owned Google service account if it's run in GCP, or set up something like Google's Workload Identity Federation to handle a K8s, AWS, or Azure deployment.

Before this commit, users could specify a hardcoded list of project IDs
to restrict access to the GCP provisioner. While this works, it can be
both toilsome to the team maintaining the Smallstep installation and
unintuitive to the internal infrastructure users that may encounter
errors as a result of their project not being added.

This commit is a rough attempt at adding support for validating that a
GCP project belongs to a given GCP organization. It does this by using
the `projects.getAncestry` call in the Cloud Resource Manager API. If
a token's project claim does not have the given organization ID as its
topmost ancestor, the token is rejected. This will require the
`resourcemanager.projects.get` IAM permission on the organization.

The new `OrganizationID` configuration directive is compatible with the
existing `ProjectIDs` configuration. If `ProjectIDs` is non-empty, it
will take precedence over the `OrganizationID` and act as it did before,
with the minor difference that if `OrganizationID` is also non-empty,
the provisioner will check the project's ancestry before rejecting the
token.

There are a couple outstanding questions and tasks after this commit. I
tried to strike the right balance between production-ready and
proof-of-concept here, so I'm open to any suggestions.

- Is the `authority/provisioner/gcp` package the right place for adding
  this functionality? Is the new struct the right approach?
- We should add tests for validating the organization ID.
- How should users configure the authentication for the Cloud Resource
  Manager client? I expect this would be similar to the Cloud KMS
  integration.
- Does Smallstep Professional run in an environment that will be able to
  authenticate with Google? We would need to either grant permissions to
  a Smallstep-owned Google service account if it's run in GCP, or set up
  something like Google's Workload Identity Federation to handle a K8s,
  AWS, or Azure deployment.
@github-actions github-actions bot added the needs triage Waiting for discussion / prioritization by team label Jan 10, 2025
@hslatman hslatman requested a review from maraino January 14, 2025 18:07
Copy link
Contributor

@maraino maraino left a comment

Choose a reason for hiding this comment

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

Hi, @ericnorris I have a question I would like to clarify

Comment on lines +52 to +56
err := p.ProjectValidator.ValidateProject(ctx, projectID)

if p.OrganizationID == "" {
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is the project validation only enforced when the organizationID is not set?

Copy link
Author

Choose a reason for hiding this comment

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

Good question - because I structured these as complementary, not mutually exclusive. I'm open to changing that, but for now it's implemented as "if you're not in the project list but an organization ID is set and you're in the organization, you're okay". I believe this would allow an incremental adoption for users already using the project ID list feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

It makes more sense to return an error even if the organization id is set.

I don't know if they are mutually exclusive, but if the project id is in the token and it doesn't match the ones in my configuration, I would expect an error.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you make that change?

Copy link
Author

@ericnorris ericnorris Jan 14, 2025

Choose a reason for hiding this comment

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

I can make that change, but let me explain - if you set the projectIDs and organizationID, would you not be confused that it was rejected when a token was in fact inside the organization?

That's what I meant by them being mutually exclusive: if it worked the way you described, you could set either projectIDs or organizationID, but not both. I was thinking about how if someone had set projectIDs today, and wanted to try out the organizationID setting, rather than completely disabling projectIDs and enabling organizationID, they could enable organizationID, try it out with a few projects, and then remove projectIDs.

Or maybe they want to allow their organization and one or a few projects from a separate organization? This would also require them to be complementary.

Again though, this is not something I personally feel strongly about, but my hunch is that this behavior is more user-friendly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs triage Waiting for discussion / prioritization by team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants