-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Terraform: add cert authority override support #69623
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| --- | ||
| title: Reference for the teleport_cert_authority_override Terraform data-source | ||
| sidebar_label: cert_authority_override | ||
| description: This page lists the supported values of the teleport_cert_authority_override data-source of the Teleport Terraform provider. | ||
| page_type: reference | ||
| --- | ||
|
|
||
| {/*Auto-generated file. Do not edit.*/} | ||
| {/*To regenerate, navigate to integrations/terraform and run `make docs`.*/} | ||
|
|
||
| {/* Disable the outdated name check since data source fields occasionally need | ||
| to refer to these. */} | ||
| {/* vale 3rd-party-products.former-names = NO */} | ||
|
|
||
| This page lists the supported values of the `teleport_cert_authority_override` data source of the | ||
| Teleport Terraform provider. | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| {/* schema generated by tfplugindocs */} | ||
| ## Schema | ||
|
|
||
| ### Optional | ||
|
|
||
| - `metadata` (Attributes) Metadata for the resource. The name of the resource is the cluster name. (see [below for nested schema](#nested-schema-for-metadata)) | ||
| - `spec` (Attributes) Spec for the resource. (see [below for nested schema](#nested-schema-for-spec)) | ||
| - `sub_kind` (String) Sub kind is the CA type. Eg: "db_client", "spiffe-tls", "windows". | ||
| - `version` (String) Version is "v1". | ||
|
|
||
| ### 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: | ||
|
|
||
| - `certificate_overrides` (Attributes List) Certificate overrides. Required. (see [below for nested schema](#nested-schema-for-speccertificate_overrides)) | ||
|
|
||
| ### Nested Schema for `spec.certificate_overrides` | ||
|
|
||
| Optional: | ||
|
|
||
| - `certificate` (String) Certificate to present, in PEM form. The public key must match an existing CA certificate. It must also match the public_key field, if present. The certificate Subject must contain the cluster name, either in the "O=" field or in OID "1.3.9999.4.1", as per RFD 0237. https://github.com/gravitational/teleport/blob/master/rfd/0237-sub-ca-support.md#subject-customization | ||
| - `chain` (List of String) Certificate chain, in PEM form. The chain must be sorted from leaf to root. If present Teleport may supply the chain, along with the certificate, in appropriate situations. The chain is limited to a generous (but sensible) server-defined length. | ||
| - `disabled` (Boolean) If true disables the override. A disabled override may exist for recording purposes, to be enabled later, or simply to mark a certain public key as not overridden. In the latter case the certificate may be absent. Disabled overrides allow CRLs to be created asynchronously, using CertAuthorityOverride watchers. | ||
| - `public_key` (String) SHA256(SubjectPublicKeyInfo DER) printed as hex string. Informative if certificate is present. | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| --- | ||
| title: Reference for the teleport_cert_authority_override Terraform resource | ||
| sidebar_label: cert_authority_override | ||
| description: This page lists the supported values of the teleport_cert_authority_override resource of the Teleport Terraform provider. | ||
| page_type: reference | ||
| --- | ||
|
|
||
| {/*Auto-generated file. Do not edit.*/} | ||
| {/*To regenerate, navigate to integrations/terraform and run `make docs`.*/} | ||
|
|
||
| {/* Disable the outdated name check since resource fields occasionally need | ||
| to refer to these. */} | ||
| {/* vale 3rd-party-products.former-names = NO */} | ||
|
|
||
| This page lists the supported values of the teleport_cert_authority_override resource of the Teleport Terraform provider. | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| {/* schema generated by tfplugindocs */} | ||
| ## Schema | ||
|
|
||
| ### Optional | ||
|
|
||
| - `metadata` (Attributes) Metadata for the resource. The name of the resource is the cluster name. (see [below for nested schema](#nested-schema-for-metadata)) | ||
| - `spec` (Attributes) Spec for the resource. (see [below for nested schema](#nested-schema-for-spec)) | ||
| - `sub_kind` (String) Sub kind is the CA type. Eg: "db_client", "spiffe-tls", "windows". | ||
| - `version` (String) Version is "v1". | ||
|
|
||
| ### 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: | ||
|
|
||
| - `certificate_overrides` (Attributes List) Certificate overrides. Required. (see [below for nested schema](#nested-schema-for-speccertificate_overrides)) | ||
|
|
||
| ### Nested Schema for `spec.certificate_overrides` | ||
|
|
||
| Optional: | ||
|
|
||
| - `certificate` (String) Certificate to present, in PEM form. The public key must match an existing CA certificate. It must also match the public_key field, if present. The certificate Subject must contain the cluster name, either in the "O=" field or in OID "1.3.9999.4.1", as per RFD 0237. https://github.com/gravitational/teleport/blob/master/rfd/0237-sub-ca-support.md#subject-customization | ||
| - `chain` (List of String) Certificate chain, in PEM form. The chain must be sorted from leaf to root. If present Teleport may supply the chain, along with the certificate, in appropriate situations. The chain is limited to a generous (but sensible) server-defined length. | ||
| - `disabled` (Boolean) If true disables the override. A disabled override may exist for recording purposes, to be enabled later, or simply to mark a certain public key as not overridden. In the latter case the certificate may be absent. Disabled overrides allow CRLs to be created asynchronously, using CertAuthorityOverride watchers. | ||
| - `public_key` (String) SHA256(SubjectPublicKeyInfo DER) printed as hex string. Informative if certificate is present. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| --- | ||
| target_package_name: "v1" | ||
| default_package_name: "github.com/gravitational/teleport/api/gen/proto/go/teleport/subca/v1" | ||
| duration_custom_type: Duration | ||
| use_state_for_unknown_by_default: true | ||
|
|
||
| # Top-level type names to export | ||
| types: | ||
| - "CertAuthorityOverride" | ||
|
|
||
| # 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: | ||
| CertAuthorityOverride: | ||
| - 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) | ||
| - "CertAuthorityOverride.status" | ||
| - "CertAuthorityOverride.metadata.id" | ||
| - "CertAuthorityOverride.metadata.revision" | ||
|
|
||
| # These fields will be marked as Computed: true | ||
| computed_fields: | ||
| # Metadata | ||
| - "CertAuthorityOverride.metadata.namespace" | ||
| - "CertAuthorityOverride.kind" | ||
|
|
||
| # These fields will be marked as Required: true | ||
| required_fields: [] | ||
|
|
||
|
|
||
| plan_modifiers: | ||
| # Force to recreate resource if its name changes | ||
| Metadata.name: | ||
| - "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()" | ||
| # sub_kind is the CA type and identifies the resource, force recreation if it changes | ||
| CertAuthorityOverride.sub_kind: | ||
| - "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: | ||
| "CertAuthorityOverride.metadata.expires": Timestamp |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| // Teleport | ||
| // Copyright (C) 2026 Gravitational, Inc. | ||
| // | ||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU Affero General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
| // | ||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU Affero General Public License for more details. | ||
| // | ||
| // You should have received a copy of the GNU Affero General Public License | ||
| // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| package resources | ||
|
|
||
| import ( | ||
| "github.com/hashicorp/terraform-plugin-framework/path" | ||
| "github.com/hashicorp/terraform-plugin-framework/tfsdk" | ||
|
|
||
| subcav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/subca/v1" | ||
| "github.com/gravitational/teleport/api/types" | ||
|
|
||
| "github.com/gravitational/teleport/integrations/terraform/provider/internal/teleport" | ||
| "github.com/gravitational/teleport/integrations/terraform/provider/internal/tfdriver" | ||
| schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/subca/v1" | ||
| ) | ||
|
|
||
| // NewCertAuthorityOverrideDataSourceType returns the cert authority override data source type. | ||
| func NewCertAuthorityOverrideDataSourceType() tfdriver.DataSourceType[subcav1.CertAuthorityOverride, tfdriver.NameIdentifier] { | ||
| return tfdriver.DataSourceType[subcav1.CertAuthorityOverride, tfdriver.NameIdentifier]{ | ||
| NewDataSourceClient: func(p tfsdk.Provider) tfdriver.DataSourceClient[subcav1.CertAuthorityOverride, tfdriver.NameIdentifier] { | ||
| return teleport.NewCertAuthorityOverrideClient(clientFromProvider(p)) | ||
| }, | ||
| Kind: types.KindCertAuthorityOverride, | ||
| Codec: tfdriver.DataSourceCodecFuncs[subcav1.CertAuthorityOverride]{ | ||
| SchemaFunc: schemav1.GenSchemaCertAuthorityOverride, | ||
| ToStateFunc: schemav1.CopyCertAuthorityOverrideToTerraform, | ||
| }, | ||
| Identifier: tfdriver.NameIdentifierFromPath(path.Root("sub_kind")), | ||
| } | ||
| } | ||
|
|
||
| // NewCertAuthorityOverrideResourceType returns the cert authority override resource type. | ||
| func NewCertAuthorityOverrideResourceType() tfdriver.ResourceType[subcav1.CertAuthorityOverride, tfdriver.NameIdentifier] { | ||
| return tfdriver.ResourceType[subcav1.CertAuthorityOverride, tfdriver.NameIdentifier]{ | ||
| NewResourceClient: func(p tfsdk.Provider) tfdriver.ResourceClient[subcav1.CertAuthorityOverride, tfdriver.NameIdentifier] { | ||
| return teleport.NewCertAuthorityOverrideClient(clientFromProvider(p)) | ||
| }, | ||
| Kind: types.KindCertAuthorityOverride, | ||
| Codec: tfdriver.ResourceCodecFuncs[subcav1.CertAuthorityOverride]{ | ||
| SchemaFunc: schemav1.GenSchemaCertAuthorityOverride, | ||
| ToStateFunc: schemav1.CopyCertAuthorityOverrideToTerraform, | ||
| FromPlanFunc: schemav1.CopyCertAuthorityOverrideFromTerraform, | ||
| }, | ||
| Normalizer: tfdriver.ForceKind[subcav1.CertAuthorityOverride](types.KindCertAuthorityOverride), | ||
| Identifier: tfdriver.NameIdentifierPolicy( | ||
| path.Root("sub_kind"), | ||
| func(override *subcav1.CertAuthorityOverride) string { | ||
| return override.GetSubKind() | ||
| }), | ||
| ResourceRevision: func(st *subcav1.CertAuthorityOverride) string { | ||
| return st.GetMetadata().GetRevision() | ||
| }, | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| // Teleport | ||
| // Copyright (C) 2026 Gravitational, Inc. | ||
| // | ||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU Affero General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
| // | ||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU Affero General Public License for more details. | ||
| // | ||
| // You should have received a copy of the GNU Affero General Public License | ||
| // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| package teleport | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/gravitational/trace" | ||
|
|
||
| "github.com/gravitational/teleport/api/client" | ||
| subcav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/subca/v1" | ||
|
|
||
| "github.com/gravitational/teleport/integrations/terraform/provider/internal/tfdriver" | ||
| ) | ||
|
|
||
| // NewCertAuthorityOverrideClient returns a cert authority override client. | ||
| func NewCertAuthorityOverrideClient(c *client.Client) CertAuthorityOverrideClient { | ||
| return CertAuthorityOverrideClient{client: c} | ||
| } | ||
|
|
||
| // CertAuthorityOverrideClient manages cert authority override resources. | ||
| type CertAuthorityOverrideClient struct { | ||
| client *client.Client | ||
| } | ||
|
|
||
| // Get reads a cert authority override by id. | ||
| func (r CertAuthorityOverrideClient) Get(ctx context.Context, id tfdriver.NameIdentifier) (*subcav1.CertAuthorityOverride, error) { | ||
| resp, err := r.client.SubCAClient().GetCertAuthorityOverride(ctx, &subcav1.GetCertAuthorityOverrideRequest{ | ||
| CaId: &subcav1.CertAuthorityOverrideID{ | ||
| CaType: id.Name, | ||
| }, | ||
| }) | ||
| if err != nil { | ||
| return nil, trace.Wrap(err) | ||
| } | ||
|
|
||
| return resp.GetCaOverride(), nil | ||
| } | ||
|
|
||
| // Create creates a cert authority override. | ||
| func (r CertAuthorityOverrideClient) Create(ctx context.Context, override *subcav1.CertAuthorityOverride) error { | ||
| if _, err := r.client.SubCAClient().CreateCertAuthorityOverride(ctx, &subcav1.CreateCertAuthorityOverrideRequest{ | ||
| CaOverride: override, | ||
| }); err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Upsert updates a cert authority override. | ||
| func (r CertAuthorityOverrideClient) Upsert(ctx context.Context, override *subcav1.CertAuthorityOverride) error { | ||
| if _, err := r.client.SubCAClient().UpsertCertAuthorityOverride(ctx, &subcav1.UpsertCertAuthorityOverrideRequest{ | ||
| CaOverride: override, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Terraform updates an existing CA override after Auth has populated AGENTS.md reference: AGENTS.md:L17-L17 Useful? React with 👍 / 👎.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is moot, but the bot can't read e/ so it can't tell. If no status is present in the request we'll simply use the last stored status. We do let callers supply the CRLs, and only the CRLs, so if you |
||
| ForceImmediateDisable: true, | ||
| }); err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Delete deletes a cert authority override by id. | ||
| func (r CertAuthorityOverrideClient) Delete(ctx context.Context, id tfdriver.NameIdentifier) error { | ||
| _, err := r.client.SubCAClient().DeleteCertAuthorityOverride(ctx, &subcav1.DeleteCertAuthorityOverrideRequest{ | ||
| CaId: &subcav1.CertAuthorityOverrideID{ | ||
| CaType: id.Name, | ||
| }, | ||
| ForceImmediateDelete: true, | ||
| }) | ||
| if err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth saying, somewhere, that cert_authority_overrides are actually identified by sub_kind + name (ie, "ca type" + "cluster name"), but that for the RPCs here the current cluster is implied as the cluster name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the exact format expected for the CaType here? Do we need more than the subkind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format is correct, we don't need anything else here.