Skip to content

Commit

Permalink
Persist Join Attributes in X509 Cert
Browse files Browse the repository at this point in the history
  • Loading branch information
strideynet committed Dec 17, 2024
1 parent cf06b70 commit bbb99df
Show file tree
Hide file tree
Showing 24 changed files with 2,750 additions and 398 deletions.
232 changes: 127 additions & 105 deletions api/gen/proto/go/teleport/machineid/v1/bot_instance.pb.go

Large diffs are not rendered by default.

171 changes: 95 additions & 76 deletions api/gen/proto/go/teleport/workloadidentity/v1/attrs.pb.go

Large diffs are not rendered by default.

1,772 changes: 1,772 additions & 0 deletions api/gen/proto/go/teleport/workloadidentity/v1/join_attrs.pb.go

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions api/proto/teleport/machineid/v1/bot_instance.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "teleport/header/v1/metadata.proto";
import "teleport/workloadidentity/v1/join_attrs.proto";

option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1;machineidv1";

Expand Down Expand Up @@ -89,12 +90,16 @@ message BotInstanceStatusAuthentication {
// Server.
google.protobuf.Timestamp authenticated_at = 1;
// The join method used for this join or renewal.
// Deprecated: prefer using join_attrs.meta.join_method
string join_method = 2;
// The join token used for this join or renewal. This is only populated for
// delegated join methods as the value for `token` join methods is sensitive.
// Deprecated: prefer using join_attrs.meta.join_token_name
string join_token = 3;
// The metadata sourced from the join method.
// Deprecated: per using join_attrs.
google.protobuf.Struct metadata = 4;

// On each renewal, this generation is incremented. For delegated join
// methods, this counter is not checked during renewal. For the `token` join
// method, this counter is checked during renewal and the Bot is locked out if
Expand All @@ -108,6 +113,9 @@ message BotInstanceStatusAuthentication {

reserved 7;
reserved "fingerprint";

// The attributes generated during the join process.
teleport.workloadidentity.v1.JoinAttrs join_attrs = 8;
}

// BotInstanceStatus holds the status of a BotInstance.
Expand Down
4 changes: 4 additions & 0 deletions api/proto/teleport/workloadidentity/v1/attrs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ syntax = "proto3";

package teleport.workloadidentity.v1;

import "teleport/workloadidentity/v1/join_attrs.proto";

option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1;workloadidentityv1";

// Attributes sourced from the Kubernetes workload attestor.
Expand Down Expand Up @@ -80,4 +82,6 @@ message Attrs {
// Attributes sourced from the user/bot making the request for a workload
// identity credential.
UserAttrs user = 2;
// Attributes resulting from the join process.
JoinAttrs join = 3;
}
312 changes: 312 additions & 0 deletions api/proto/teleport/workloadidentity/v1/join_attrs.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
// Copyright 2024 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package teleport.workloadidentity.v1;

option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1;workloadidentityv1";

// The collection of attributes that result from the join process.
message JoinAttrs {
// The collection of attributes that result from the join process but are not
// specific to any particular join method.
JoinAttrsMeta meta = 1;
// Attributes that are specific to the GitLab (`gitlab`) join method.
JoinAttrsGitLab gitlab = 2;
// Attributes that are specific to the GitHub (`github`) join method.
JoinAttrsGitHub github = 3;
// Attributes that are specific to the AWS IAM (`iam`) join method.
JoinAttrsAWSIAM iam = 4;
// Attributes that are specific to the TPM (`tpm`) join method.
JoinAttrsTPM tpm = 5;
// Attributes that are specific to the Azure (`azure`) join method.
JoinAttrsAzure azure = 6;
// Attributes that are specific to the CircleCI (`circleci`) join method.
JoinAttrsCircleCI circleci = 7;
// Attributes that are specific to the Bitbucket (`bitbucket`) join method.
JoinAttrsBitbucket bitbucket = 8;
// Attributes that are specific to the Terraform Cloud (`terraform_cloud`) join method.
JoinAttrsTerraformCloud terraform_cloud = 9;
// Attributes that are specific to the Spacelift (`spacelift`) join method.
JoinAttrsSpacelift spacelift = 10;
// Attributes that are specific to the GCP (`gcp`) join method.
JoinAttrsGCP gcp = 11;
// Attributes that are specific to the Kubernetes (`kubernetes`) join method.
JoinAttrsKubernetes kubernetes = 12;
}

// The collection of attributes that result from the join process but are not
// specific to any particular join method.
message JoinAttrsMeta {
// The name of the join token that was used to join.
//
// This field is omitted if the join token that was used to join was of the
// `token` method as in this case, the name of the join token is sensitive.
//
// Example: `my-gitlab-join-token`
string join_token_name = 1;
// The name of the join method that was used to join.
//
// Example: `gitlab`
string join_method = 2;
}

// Attributes that are specific to the GitLab join method.
//
// Typically, these are mapped directly from the claims of the GitLab JWT that
// was used to join. You can view the documentation for those claims at:
// https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#token-payload
message JoinAttrsGitLab {
// The `sub` claim of the GitLab JWT that was used to join.
// For example: `project_path:mygroup/my-project:ref_type:branch:ref:main`
string sub = 1;
// The ref that the pipeline is running against.
// For example: `main`
string ref = 2;
// The type of ref that the pipeline is running against.
// This is typically `branch` or `tag`.
string ref_type = 3;
// Whether or not the ref that the pipeline is running against is protected.
bool ref_protected = 4;
// The path of the namespace of the project that the pipeline is running within.
// For example: `mygroup`
string namespace_path = 5;
// The full qualified path of the project that the pipeline is running within.
// This includes the namespace path.
// For example: `mygroup/my-project`
string project_path = 6;
// The name of the user that triggered the pipeline run.
string user_login = 7;
// The email of the user that triggered the pipeline run.
string user_email = 8;
// The ID of the pipeline.
string pipeline_id = 9;
// The source of the pipeline.
// For example: `push` or `web`
string pipeline_source = 10;
// The environment the pipeline is running against, if any.
string environment = 11;
// Whether or not the pipeline is running against a protected environment.
// If there is no configured environment, this field is false.
bool environment_protected = 12;
// The ID of the runner that this pipeline is running on.
int64 runner_id = 13;
// The type of runner that is processing the pipeline.
// Either `gitlab-hosted` or `self-hosted`.
string runner_environment = 14;
// The SHA of the commit that triggered the pipeline run.
string sha = 15;
// The ref URI of the CI config configuring the pipeline.
string ci_config_ref_uri = 16;
// The Git SHA of the CI config ref configuring the pipeline.
string ci_config_sha = 17;
}

// Attributes that are specific to the GitHub (`github`) join method.
//
// Typically, these are mapped directly from the claims of the GitHub JWT that
// was used to join. You can view the documentation for those claims at:
// https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#understanding-the-oidc-token
message JoinAttrsGitHub {
// The `sub` claim of the GitHub JWT that was used to join.
string sub = 1;
// The username of the actor that initiated the workflow run.
string actor = 2;
// The name of the environment that the workflow is running against, if any.
string environment = 3;
// The ref that the workflow is running against.
string ref = 4;
// The type of ref that the workflow is running against.
// For example, `branch`.
string ref_type = 5;
// The name of the repository that the workflow is running within.
string repository = 6;
// The name of the owner of the repository that the workflow is running within.
string repository_owner = 7;
// The name of the workflow that is running.
string workflow = 8;
// The name of the event that triggered the workflow run.
string event_name = 9;
// The SHA of the commit that triggered the workflow run.
string sha = 10;
// The ID of this GitHub actions workflow run.
string run_id = 11;
}

// Attributes that are specific to the AWS IAM (`iam`) join method.
//
// Typically, these are mapped directly from the results of the
// STS GetCallerIdentity call that is made as part of the join process.
message JoinAttrsAWSIAM {
// The identifier of the account that the joining entity is a part of.
// For example: `123456789012`
string account = 1;
// The AWS ARN of the joining entity.
// For example: `arn:aws:sts::123456789012:assumed-role/my-role-name/my-role-session-name`
string arn = 2;
}

// Attributes that are specific to the TPM (`tpm`) join method.
message JoinAttrsTPM {
// The SHA256 hash of the PKIX formatted EK public key, encoded in hex.
// This effectively identifies a specific TPM.
string ek_pub_hash = 1;
// The serial number of the EK certificate, if present.
string ek_cert_serial = 2;
// Whether or not the EK certificate was verified against a certificate
// authority.
bool ek_cert_verified = 3;
}

// Attributes that are specific to the Azure (`azure`) join method.
message JoinAttrsAzure {
// The subscription ID of the Azure account that the joining entity is a part of.
string subscription = 1;
// The resource group of the Azure account that the joining entity is a part of.
string resource_group = 2;
}

// Attributes that are specific to the CircleCI (`circleci`) join method.
// These are mapped from the claims of the JWT issued by CircleCI to runs,
// which is documented at: https://circleci.com/docs/openid-connect-tokens/
message JoinAttrsCircleCI {
// The `sub` claim of the CircleCI JWT that was used to join.
// For example: `org/ORGANIZATION_ID/project/PROJECT_ID/user/USER_ID`
string sub = 1;
// The UUIDs of the contexts used in the job.
repeated string context_ids = 2;
// The UUID of the project in which the job is running.
string project_id = 3;
}

// Attributes that are specific to the Bitbucket (`bitbucket`) join method.
// These are mapped from the claims of the JWT issued by BitBucket to runs,
// which is documented at: https://support.atlassian.com/bitbucket-cloud/docs/integrate-pipelines-with-resource-servers-using-oidc/
message JoinAttrsBitbucket {
// The `sub` claim of the Bitbucket JWT that was used to join.
string sub = 1;
// The UUID of the pipeline step.
string step_uuid = 2;
// The UUID of the repository the pipeline step is running within.
string repository_uuid = 3;
// The UUID of the pipeline the step is running within.
string pipeline_uuid = 4;
// The UUID of the workspace the pipeline belongs to.
string workspace_uuid = 5;
// The UUID of the deployment environment the pipeline is running against.
string deployment_environment_uuid = 6;
// The name of the branch the pipeline is running against.
string branch_name = 7;
}

// Attributes that are specific to the Terraform Cloud (`terraform_cloud`) join method.
// These are mapped from the claims of the JWT issued by Terraform Cloud to runs,
// which is documented at: https://developer.hashicorp.com/terraform/enterprise/workspaces/dynamic-provider-credentials/workload-identity-tokens
message JoinAttrsTerraformCloud {
// The `sub` claim of the Terraform Cloud JWT that was used to join.
string sub = 1;
// The name of the organization the project and workspace belong to.
string organization_name = 2;
// The name of the project the workspace belongs to.
string project_name = 3;
// The name of the workspace that the plan/apply is running within.
string workspace_name = 4;
// The fully qualified workspace path, including the organization and project
// name.
// For example: `organization:<name>:project:<name>:workspace:<name>`
string full_workspace = 5;
// The ID of the run that is being executed.
string run_id = 6;
// The phase of the run that is being executed, either `plan` or `apply`.
string run_phase = 7;
}

// Attributes that are specific to the Spacelift (`spacelift`) join method.
// These are mapped from the claims of the JWT issued by Spacelift to runs,
// which is documented at: https://docs.spacelift.io/integrations/cloud-providers/oidc/#standard-claims
message JoinAttrsSpacelift {
// The `sub` claim of the Spacelift JWT that was used to join.
string sub = 1;
// The ID of the space in which the run is executing.
string space_id = 2;
// The type of the caller that owns the run, either `stack` or `module`.
string caller_type = 3;
// The ID of the caller that generated the run.
string caller_id = 4;
// The type of the run, either `PROPOSED`, `TRACKED`, `TASK`, `TESTING` or `DESTROY`.
string run_type = 5;
// The ID of the run.
string run_id = 6;
// The configured scope of the token, either `read` or `write`.
string scope = 7;
}

// Attributes specific to the GCP join method when the joining entity is on a
// GCE instance.
message JoinAttrsGCPGCE {
// The name of the GCE instance that the joining entity is running on.
string name = 1;
// The zone of the GCE instance that the joining entity is running on.
string zone = 2;
// The ID of the GCE instance that the joining entity is running on.
string id = 3;
// The project ID of the GCP project that the instance is running within.
string project = 4;
}

// Attributes that are specific to the GCP (`gcp`) join method.
// These are mapped from the claims of the JWT instance identity token, which
// is documented at: https://cloud.google.com/compute/docs/instances/verifying-instance-identity#payload
message JoinAttrsGCP {
// The service account email of the service account that the instance is running as.
string service_account = 1;
// Attributes specific to the GCP join method when the joining entity is on a
// GCE instance. This may not be present if the joining entity is not on
// GCE.
JoinAttrsGCPGCE gce = 2;
}

// Attributes that are specific to the Kubernetes (`kubernetes`) join method
// when a pod-bound service account token is used.
message JoinAttrsKubernetesPod {
// The name of the service account that the joining entity is running as.
string name = 1;
}

// Attributes that are specific to the Kubernetes (`kubernetes`) join method
// when a service account token is used.
message JoinAttrsKubernetesServiceAccount {
// The name of the service account that the joining entity is running as.
string name = 1;
// The namespace of the service account that the joining entity is running as.
string namespace = 2;
}

// Attributes that are specific to the Kubernetes (`kubernetes`) join method.
message JoinAttrsKubernetes {
// The fully qualified identifier of the entity based on the Kubernetes
// token. For a service account, this takes the form of
// `system:serviceaccount:<namespace>:<service-account-name>`.
string subject = 1;
// Attributes specific to the Kubernetes join method when the joining entity
// is a service account token. This will only be present if the joining entity
// is a service account (as opposed to a human user or similar).
JoinAttrsKubernetesServiceAccount service_account = 2;
// Attributes specific to the Kubernetes join method when the joining entity
// is a pod-bound service account token. This will only be present if the
// joining entity is a service account, and, the token has been bound to a
// pod.
JoinAttrsKubernetesPod pod = 3;
}
7 changes: 6 additions & 1 deletion lib/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import (
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1"
notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
workloadidentityv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1"
"github.com/gravitational/teleport/api/internalutils/stream"
"github.com/gravitational/teleport/api/metadata"
"github.com/gravitational/teleport/api/types"
Expand Down Expand Up @@ -2276,6 +2277,9 @@ type certRequest struct {
// botInstanceID is the unique identifier of the bot instance associated
// with this cert, if any
botInstanceID string
// joinAttributes holds attributes derived from attested metadata from the
// join process, should any exist.
joinAttributes *workloadidentityv1pb.JoinAttrs
}

// check verifies the cert request is valid.
Expand Down Expand Up @@ -3356,7 +3360,8 @@ func generateCert(ctx context.Context, a *Server, req certRequest, caType types.
AssetTag: req.deviceExtensions.AssetTag,
CredentialID: req.deviceExtensions.CredentialID,
},
UserType: req.user.GetUserType(),
UserType: req.user.GetUserType(),
JoinAttributes: req.joinAttributes,
}

var signedTLSCert []byte
Expand Down
Loading

0 comments on commit bbb99df

Please sign in to comment.