Skip to content
Closed
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
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
Expand Up @@ -21,6 +21,7 @@ The Teleport Terraform provider supports the following data-sources:
- [`teleport_auth_preference`](./auth_preference.mdx)
- [`teleport_autoupdate_config`](./autoupdate_config.mdx)
- [`teleport_autoupdate_version`](./autoupdate_version.mdx)
- [`teleport_cert_authority_override`](./cert_authority_override.mdx)
- [`teleport_classifier`](./classifier.mdx)
- [`teleport_client_ip_restriction`](./client_ip_restriction.mdx)
- [`teleport_cluster_maintenance_config`](./cluster_maintenance_config.mdx)
Expand Down
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
Expand Up @@ -22,6 +22,7 @@ The Teleport Terraform provider supports the following resources:
- [`teleport_autoupdate_config`](./autoupdate_config.mdx)
- [`teleport_autoupdate_version`](./autoupdate_version.mdx)
- [`teleport_bot`](./bot.mdx)
- [`teleport_cert_authority_override`](./cert_authority_override.mdx)
- [`teleport_classifier`](./classifier.mdx)
- [`teleport_client_ip_restriction`](./client_ip_restriction.mdx)
- [`teleport_cluster_maintenance_config`](./cluster_maintenance_config.mdx)
Expand Down
8 changes: 8 additions & 0 deletions integrations/terraform/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ gen-tfschema:
--terraform_out=config=protoc-gen-terraform-workloadidentity.yaml:./tfschema \
teleport/workloadidentity/v1/resource.proto

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

@protoc \
-I=../../api/proto \
-I=$(PROTOBUF_MOD_PATH) \
Expand Down Expand Up @@ -215,6 +222,7 @@ gen-tfschema:
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule_terraform.go ./tfschema/dbobjectimportrule/v1/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/clientiprestriction/v1/clientiprestriction_terraform.go ./tfschema/clientiprestriction/v1/
mv ./tfschema/github.com/gravitational/teleport/api/types/device_terraform.go ./tfschema/devicetrust/v1/
mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/subca/v1/cert_authority_override_terraform.go ./tfschema/subca/v1/
rm -r ./tfschema/github.com/

grep -rl 'Code generated by _gen/main.go DO NOT EDIT' --include='*.go' ./provider/internal/legacy | xargs -r rm
Expand Down
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,

Copy link
Copy Markdown
Contributor

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?

Copy link
Copy Markdown
Contributor Author

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?

Copy link
Copy Markdown
Contributor

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.

},
})
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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve CA override status when updating

When Terraform updates an existing CA override after Auth has populated status.public_key_hash_to_crl (the async CRL path used for disabled overrides in multi-Auth/HSM clusters), the plan decoded from Terraform has status omitted because it is excluded from the schema, and this Upsert sends that object as the full replacement. That can drop server-managed CRLs during a harmless metadata/spec reconciliation and corrupt the override's revocation state; preserve the prior status in PrepareUpdate or use a merge/granular update path.

AGENTS.md reference: AGENTS.md:L17-L17

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 tctl get an old override you can re-create it verbatim.

https://github.com/gravitational/teleport.e/blob/c396029d68aa96db4efa4a8b1e64c73568ea4206/lib/subca/subcav1/service.go#L1041-L1053

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
}
Loading
Loading