Skip to content

Commit

Permalink
Add support for WorkloadIdentity resource to the Teleport Terraform P…
Browse files Browse the repository at this point in the history
…rovider (#50382)

* First pass at trying to generate terraform provider

* Wire up types

* Fix generation of docs

* Add godoc comments

* Add tests

* Tflint and add example
  • Loading branch information
strideynet authored Dec 20, 2024
1 parent b1b6bb2 commit 3796023
Show file tree
Hide file tree
Showing 17 changed files with 2,124 additions and 0 deletions.
46 changes: 46 additions & 0 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5097,6 +5097,52 @@ func (c *Client) UpsertUserLastSeenNotification(ctx context.Context, req *notifi
return rsp, trace.Wrap(err)
}

// GetWorkloadIdentity returns a workload identity by name.
func (c *Client) GetWorkloadIdentity(ctx context.Context, name string) (*workloadidentityv1pb.WorkloadIdentity, error) {
resp, err := c.WorkloadIdentityResourceServiceClient().GetWorkloadIdentity(ctx, &workloadidentityv1pb.GetWorkloadIdentityRequest{
Name: name,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// DeleteWorkloadIdentity deletes a workload identity by name. It will throw an
// error if the workload identity does not exist.
func (c *Client) DeleteWorkloadIdentity(ctx context.Context, name string) error {
_, err := c.WorkloadIdentityResourceServiceClient().DeleteWorkloadIdentity(ctx, &workloadidentityv1pb.DeleteWorkloadIdentityRequest{
Name: name,
})
if err != nil {
return trace.Wrap(err)
}
return nil
}

// CreateWorkloadIdentity creates a new workload identity, it will not overwrite
// an existing workload identity with the same name.
func (c *Client) CreateWorkloadIdentity(ctx context.Context, r *workloadidentityv1pb.WorkloadIdentity) (*workloadidentityv1pb.WorkloadIdentity, error) {
resp, err := c.WorkloadIdentityResourceServiceClient().CreateWorkloadIdentity(ctx, &workloadidentityv1pb.CreateWorkloadIdentityRequest{
WorkloadIdentity: r,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// UpsertWorkloadIdentity creates or updates a workload identity.
func (c *Client) UpsertWorkloadIdentity(ctx context.Context, r *workloadidentityv1pb.WorkloadIdentity) (*workloadidentityv1pb.WorkloadIdentity, error) {
resp, err := c.WorkloadIdentityResourceServiceClient().UpsertWorkloadIdentity(ctx, &workloadidentityv1pb.UpsertWorkloadIdentityRequest{
WorkloadIdentity: r,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// ResourceUsageClient returns an unadorned Resource Usage service client,
// using the underlying Auth gRPC connection.
// Clients connecting to non-Enterprise clusters, or older Teleport versions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ The Teleport Terraform provider supports the following data-sources:
- [`teleport_trusted_cluster`](./trusted_cluster.mdx)
- [`teleport_trusted_device`](./trusted_device.mdx)
- [`teleport_user`](./user.mdx)
- [`teleport_workload_identity`](./workload_identity.mdx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: Reference for the teleport_workload_identity Terraform data-source
sidebar_label: workload_identity
description: This page describes the supported values of the teleport_workload_identity data-source of the Teleport Terraform provider.
---

{/*Auto-generated file. Do not edit.*/}
{/*To regenerate, navigate to integrations/terraform and run `make docs`.*/}





{/* schema generated by tfplugindocs */}
## Schema

### Optional

- `metadata` (Attributes) Common metadata that all resources share. (see [below for nested schema](#nested-schema-for-metadata))
- `spec` (Attributes) The configured properties of the WorkloadIdentity (see [below for nested schema](#nested-schema-for-spec))
- `sub_kind` (String) Differentiates variations of the same kind. All resources should contain one, even if it is never populated.
- `version` (String) The version of the resource being represented.

### Nested Schema for `metadata`

Optional:

- `description` (String) description is object description.
- `expires` (String) expires is a global expiry time header can be set on any resource in the system.
- `labels` (Map of String) labels is a set of labels.
- `name` (String) name is an object name.


### Nested Schema for `spec`

Optional:

- `rules` (Attributes) The rules which are evaluated before the WorkloadIdentity can be issued. (see [below for nested schema](#nested-schema-for-specrules))
- `spiffe` (Attributes) Configuration pertaining to the issuance of SPIFFE-compatible workload identity credentials. (see [below for nested schema](#nested-schema-for-specspiffe))

### Nested Schema for `spec.rules`

Optional:

- `allow` (Attributes List) A list of rules used to determine if a WorkloadIdentity can be issued. If none are provided, it will be considered a pass. If any are provided, then at least one must pass for the rules to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallow))

### Nested Schema for `spec.rules.allow`

Optional:

- `conditions` (Attributes List) The conditions that must be met for this rule to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallowconditions))

### Nested Schema for `spec.rules.allow.conditions`

Optional:

- `attribute` (String) The name of the attribute to evaluate the condition against.
- `equals` (String) An exact string that the attribute must match.




### Nested Schema for `spec.spiffe`

Optional:

- `hint` (String) A freeform text field which is provided to workloads along with a credential produced by this WorkloadIdentity. This can be used to provide additional context that can be used to select between multiple credentials.
- `id` (String) The path of the SPIFFE ID that will be issued to the workload. This should be prefixed with a forward-slash ("/"). This field supports templating using attributes.

Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ The Teleport Terraform provider supports the following resources:
- [`teleport_trusted_cluster`](./trusted_cluster.mdx)
- [`teleport_trusted_device`](./trusted_device.mdx)
- [`teleport_user`](./user.mdx)
- [`teleport_workload_identity`](./workload_identity.mdx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
title: Reference for the teleport_workload_identity Terraform resource
sidebar_label: workload_identity
description: This page describes the supported values of the teleport_workload_identity resource of the Teleport Terraform provider.
---

{/*Auto-generated file. Do not edit.*/}
{/*To regenerate, navigate to integrations/terraform and run `make docs`.*/}



## Example Usage

```hcl
resource "teleport_workload_identity" "example" {
version = "v1"
metadata = {
name = "example"
}
spec = {
rules = {
allow = [
{
conditions = [{
attribute = "user.name"
equals = "noah"
}]
}
]
}
spiffe = {
id = "/my/spiffe/id/path"
hint = "my-hint"
}
}
}
```

{/* schema generated by tfplugindocs */}
## Schema

### Optional

- `metadata` (Attributes) Common metadata that all resources share. (see [below for nested schema](#nested-schema-for-metadata))
- `spec` (Attributes) The configured properties of the WorkloadIdentity (see [below for nested schema](#nested-schema-for-spec))
- `sub_kind` (String) Differentiates variations of the same kind. All resources should contain one, even if it is never populated.
- `version` (String) The version of the resource being represented.

### Nested Schema for `metadata`

Optional:

- `description` (String) description is object description.
- `expires` (String) expires is a global expiry time header can be set on any resource in the system.
- `labels` (Map of String) labels is a set of labels.
- `name` (String) name is an object name.


### Nested Schema for `spec`

Optional:

- `rules` (Attributes) The rules which are evaluated before the WorkloadIdentity can be issued. (see [below for nested schema](#nested-schema-for-specrules))
- `spiffe` (Attributes) Configuration pertaining to the issuance of SPIFFE-compatible workload identity credentials. (see [below for nested schema](#nested-schema-for-specspiffe))

### Nested Schema for `spec.rules`

Optional:

- `allow` (Attributes List) A list of rules used to determine if a WorkloadIdentity can be issued. If none are provided, it will be considered a pass. If any are provided, then at least one must pass for the rules to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallow))

### Nested Schema for `spec.rules.allow`

Optional:

- `conditions` (Attributes List) The conditions that must be met for this rule to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallowconditions))

### Nested Schema for `spec.rules.allow.conditions`

Optional:

- `attribute` (String) The name of the attribute to evaluate the condition against.
- `equals` (String) An exact string that the attribute must match.




### Nested Schema for `spec.spiffe`

Optional:

- `hint` (String) A freeform text field which is provided to workloads along with a credential produced by this WorkloadIdentity. This can be used to provide additional context that can be used to select between multiple credentials.
- `id` (String) The path of the SPIFFE ID that will be issued to the workload. This should be prefixed with a forward-slash ("/"). This field supports templating using attributes.

8 changes: 8 additions & 0 deletions integrations/terraform/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,18 @@ endif
--terraform_out=config=protoc-gen-terraform-statichostuser.yaml:./tfschema \
teleport/userprovisioning/v2/statichostuser.proto

@protoc \
-I=../../api/proto \
-I=$(PROTOBUF_MOD_PATH) \
--plugin=$(PROTOC_GEN_TERRAFORM) \
--terraform_out=config=protoc-gen-terraform-workloadidentity.yaml:./tfschema \
teleport/workloadidentity/v1/resource.proto

mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1/loginrule_terraform.go ./tfschema/loginrule/v1/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1/accesslist_terraform.go ./tfschema/accesslist/v1/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_terraform.go ./tfschema/accessmonitoringrules/v1/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser_terraform.go ./tfschema/userprovisioning/v2/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1/resource_terraform.go ./tfschema/workloadidentity/v1/
mv ./tfschema/github.com/gravitational/teleport/api/types/device_terraform.go ./tfschema/devicetrust/v1/
rm -r ./tfschema/github.com/
@go run ./gen/main.go
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
resource "teleport_workload_identity" "example" {
version = "v1"
metadata = {
name = "example"
}
spec = {
rules = {
allow = [
{
conditions = [{
attribute = "user.name"
equals = "noah"
}]
}
]
}
spiffe = {
id = "/my/spiffe/id/path"
hint = "my-hint"
}
}
}
27 changes: 27 additions & 0 deletions integrations/terraform/gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,31 @@ var (
ExtraImports: []string{"apitypes \"github.com/gravitational/teleport/api/types\""},
ForceSetKind: "apitypes.KindStaticHostUser",
}

workloadIdentity = payload{
Name: "WorkloadIdentity",
TypeName: "WorkloadIdentity",
VarName: "workloadIdentity",
GetMethod: "GetWorkloadIdentity",
CreateMethod: "CreateWorkloadIdentity",
UpsertMethodArity: 2,
UpdateMethod: "UpsertWorkloadIdentity",
DeleteMethod: "DeleteWorkloadIdentity",
ID: "workloadIdentity.Metadata.Name",
Kind: "workload_identity",
HasStaticID: false,
ProtoPackage: "workloadidentityv1",
ProtoPackagePath: "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1",
SchemaPackage: "schemav1",
SchemaPackagePath: "github.com/gravitational/teleport/integrations/terraform/tfschema/workloadidentity/v1",
TerraformResourceType: "teleport_workload_identity",
// Since [RFD 153](https://github.com/gravitational/teleport/blob/master/rfd/0153-resource-guidelines.md)
// resources are plain structs
IsPlainStruct: true,
// As 153-style resources don't have CheckAndSetDefaults, we must set the Kind manually.
// We import the package containing kinds, then use ForceSetKind.
ForceSetKind: `"workload_identity"`,
}
)

func main() {
Expand Down Expand Up @@ -570,6 +595,8 @@ func genTFSchema() {
generateDataSource(accessMonitoringRule, pluralDataSource)
generateResource(staticHostUser, pluralResource)
generateDataSource(staticHostUser, pluralDataSource)
generateResource(workloadIdentity, pluralResource)
generateDataSource(workloadIdentity, pluralDataSource)
}

func generateResource(p payload, tpl string) {
Expand Down
68 changes: 68 additions & 0 deletions integrations/terraform/protoc-gen-terraform-workloadidentity.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
target_package_name: "v1"
default_package_name: "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1"
duration_custom_type: Duration
use_state_for_unknown_by_default: true

# Top-level type names to export
types:
- "WorkloadIdentity"

# These import paths were not being automatically picked up by
# protoc-gen-terraform without these overrides
import_path_overrides:
"types": "github.com/gravitational/teleport/api/types"
"wrappers": "github.com/gravitational/teleport/api/types/wrappers"
"durationpb": "google.golang.org/protobuf/types/known/durationpb"
"timestamppb": "google.golang.org/protobuf/types/known/timestamppb"
"structpb": "google.golang.org/protobuf/types/known/structpb"
"v1": "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
"v11": "github.com/gravitational/teleport/api/gen/proto/go/teleport/label/v1"
"github_com_gravitational_teleport_integrations_terraform_tfschema": "github.com/gravitational/teleport/integrations/terraform/tfschema"


# id field is required for integration tests. It is not used by provider.
# We have to add it manually (might be removed in the future versions).
injected_fields:
WorkloadIdentity:
- name: id
type: github.com/hashicorp/terraform-plugin-framework/types.StringType
computed: true
plan_modifiers:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()"

# These fields will be excluded
exclude_fields:
# Metadata (we id resources by name on our side)
- "WorkloadIdentity.metadata.id"

# These fields will be marked as Computed: true
computed_fields:
# Metadata
- "WorkloadIdentity.metadata.namespace"
- "WorkloadIdentity.kind"

# These fields will be marked as Required: true
required_fields: []


plan_modifiers:
# Force to recreate resource if it's name changes
Metadata.name:
- "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()"

# This must be defined for the generator to be happy, but in reality all time
# fields are overridden (because the protobuf timestamps contain locks and the
# linter gets mad if we use raw structs instead of pointers).
time_type:
type: "PlaceholderType"
duration_type:
type: "PlaceholderType"

validators:
# Expires must be in the future
Metadata.expires:
- github_com_gravitational_teleport_integrations_terraform_tfschema.MustTimeBeInFuture()

custom_types:
"WorkloadIdentity.metadata.expires": Timestamp
Loading

0 comments on commit 3796023

Please sign in to comment.