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

[v17] Machine ID: Add bitbucket join method for Bitbucket Pipelines joining (#48724) #49335

Merged
merged 1 commit into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions api/proto/teleport/legacy/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,8 @@ message ProvisionTokenSpecV2 {
ProvisionTokenSpecV2TPM TPM = 15 [(gogoproto.jsontag) = "tpm,omitempty"];
// TerraformCloud allows the configuration of options specific to the "terraform_cloud" join method.
ProvisionTokenSpecV2TerraformCloud TerraformCloud = 16 [(gogoproto.jsontag) = "terraform_cloud,omitempty"];
// Bitbucket allows the configuration of options specific to the "bitbucket" join method.
ProvisionTokenSpecV2Bitbucket Bitbucket = 17 [(gogoproto.jsontag) = "bitbucket,omitempty"];
}

// ProvisionTokenSpecV2TPM contains the TPM-specific part of the
Expand Down Expand Up @@ -1666,6 +1668,49 @@ message ProvisionTokenSpecV2TerraformCloud {
string Hostname = 3 [(gogoproto.jsontag) = "hostname,omitempty"];
}

message ProvisionTokenSpecV2Bitbucket {
// Rule is a set of properties the Bitbucket-issued token might have to be
// allowed to use this ProvisionToken.
message Rule {
// WorkspaceUUID is the UUID of the workspace for which this token was
// issued. Bitbucket UUIDs must begin and end with braces, e.g. `{...}`.
// This value may be found in the Pipelines -> OpenID Connect section of the
// repository settings.
string WorkspaceUUID = 1 [(gogoproto.jsontag) = "workspace_uuid,omitempty"];

// RepositoryUUID is the UUID of the repository for which this token was
// issued. Bitbucket UUIDs must begin and end with braces, e.g. `{...}`.
// This value may be found in the Pipelines -> OpenID Connect section of the
// repository settings.
string RepositoryUUID = 2 [(gogoproto.jsontag) = "repository_uuid,omitempty"];

// DeploymentEnvironmentUUID is the UUID of the deployment environment
// targeted by this pipelines run, if any. These values may be found in the
// "Pipelines -> OpenID Connect -> Deployment environments" section of the
// repository settings.
string DeploymentEnvironmentUUID = 3 [(gogoproto.jsontag) = "deployment_environment_uuid,omitempty"];

// BranchName is the name of the branch on which this pipeline executed.
string BranchName = 4 [(gogoproto.jsontag) = "branch_name,omitempty"];
}

// Allow is a list of Rules, nodes using this token must match one
// allow rule to use this token.
repeated Rule Allow = 1 [(gogoproto.jsontag) = "allow,omitempty"];

// Audience is a Bitbucket-specified audience value for this token. It is
// unique to each Bitbucket repository, and must be set to the value as
// written in the Pipelines -> OpenID Connect section of the repository
// settings.
string Audience = 2 [(gogoproto.jsontag) = "audience,omitempty"];

// IdentityProviderURL is a Bitbucket-specified issuer URL for incoming OIDC
// tokens. It is unique to each Bitbucket repository, and must be set to the
// value as written in the Pipelines -> OpenID Connect section of the
// repository settings.
string IdentityProviderURL = 3 [(gogoproto.jsontag) = "identity_provider_url,omitempty"];
}

// StaticTokensV2 implements the StaticTokens interface.
message StaticTokensV2 {
option (gogoproto.goproto_stringer) = false;
Expand Down
42 changes: 42 additions & 0 deletions api/types/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ const (
// JoinMethodTerraformCloud indicates that the node will join using the Terraform
// join method. See lib/terraformcloud for more.
JoinMethodTerraformCloud JoinMethod = "terraform_cloud"
// JoinMethodBitbucket indicates that the node will join using the Bitbucket
// join method. See lib/bitbucket for more.
JoinMethodBitbucket JoinMethod = "bitbucket"
)

var JoinMethods = []JoinMethod{
Expand Down Expand Up @@ -363,6 +366,17 @@ func (p *ProvisionTokenV2) CheckAndSetDefaults() error {
if err := providerCfg.checkAndSetDefaults(); err != nil {
return trace.Wrap(err, "spec.terraform_cloud: failed validation")
}
case JoinMethodBitbucket:
providerCfg := p.Spec.Bitbucket
if providerCfg == nil {
return trace.BadParameter(
"spec.bitbucket: must be configured for the join method %q",
JoinMethodBitbucket,
)
}
if err := providerCfg.checkAndSetDefaults(); err != nil {
return trace.Wrap(err, "spec.bitbucket: failed validation")
}
default:
return trace.BadParameter("unknown join method %q", p.Spec.JoinMethod)
}
Expand Down Expand Up @@ -862,3 +876,31 @@ func (a *ProvisionTokenSpecV2TerraformCloud) checkAndSetDefaults() error {

return nil
}

func (a *ProvisionTokenSpecV2Bitbucket) checkAndSetDefaults() error {
if len(a.Allow) == 0 {
return trace.BadParameter("the %q join method requires at least one token allow rule", JoinMethodBitbucket)
}

if a.Audience == "" {
return trace.BadParameter("audience: an OpenID Connect Audience value is required")
}

if a.IdentityProviderURL == "" {
return trace.BadParameter("identity_provider_url: an identity provider URL is required")
}

for i, rule := range a.Allow {
workspaceSet := rule.WorkspaceUUID != ""
repositorySet := rule.RepositoryUUID != ""

if !workspaceSet && !repositorySet {
return trace.BadParameter(
"allow[%d]: at least one of ['workspace_uuid', 'repository_uuid'] must be set",
i,
)
}
}

return nil
}
108 changes: 108 additions & 0 deletions api/types/provisioning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,114 @@ func TestProvisionTokenV2_CheckAndSetDefaults(t *testing.T) {
},
wantErr: true,
},
{
desc: "bitbucket only workspace",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodBitbucket,
Bitbucket: &ProvisionTokenSpecV2Bitbucket{
Audience: "foo",
IdentityProviderURL: "https://example.com",
Allow: []*ProvisionTokenSpecV2Bitbucket_Rule{
{
WorkspaceUUID: "{foo}",
},
},
},
},
},
wantErr: false,
},
{
desc: "bitbucket only repository",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodBitbucket,
Bitbucket: &ProvisionTokenSpecV2Bitbucket{
Audience: "foo",
IdentityProviderURL: "https://example.com",
Allow: []*ProvisionTokenSpecV2Bitbucket_Rule{
{
RepositoryUUID: "{foo}",
},
},
},
},
},
wantErr: false,
},
{
desc: "bitbucket missing audience",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodBitbucket,
Bitbucket: &ProvisionTokenSpecV2Bitbucket{
IdentityProviderURL: "https://example.com",
Allow: []*ProvisionTokenSpecV2Bitbucket_Rule{
{
WorkspaceUUID: "{foo}",
},
},
},
},
},
wantErr: true,
},
{
desc: "bitbucket missing identity provider",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodBitbucket,
Bitbucket: &ProvisionTokenSpecV2Bitbucket{
Audience: "foo",
Allow: []*ProvisionTokenSpecV2Bitbucket_Rule{
{
WorkspaceUUID: "{foo}",
},
},
},
},
},
wantErr: true,
},
{
desc: "bitbucket missing workspace or repository",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodBitbucket,
Bitbucket: &ProvisionTokenSpecV2Bitbucket{
Audience: "foo",
IdentityProviderURL: "https://example.com",
Allow: []*ProvisionTokenSpecV2Bitbucket_Rule{
{
DeploymentEnvironmentUUID: "{foo}",
},
},
},
},
},
wantErr: true,
},
}

for _, tc := range testcases {
Expand Down
Loading
Loading