mirror of
https://github.com/hashicorp/terraform-provider-kubernetes.git
synced 2025-12-18 23:06:07 -05:00
Add ephemeral resources: kubernetes_token_request_v1, kubernetes_certificate_signing_request_v1 (#2628)
This commit is contained in:
parent
ec878df352
commit
b0a4fb976a
21 changed files with 965 additions and 256 deletions
5
.changelog/2628.txt
Normal file
5
.changelog/2628.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
```release-note:enhancement
|
||||
FEATURES:
|
||||
* New ephemeral resource: `kubernetes_certificate_signing_request_v1`
|
||||
* New ephemeral resource: `kubernetes_token_request_v1`
|
||||
```
|
||||
1
.github/workflows/acceptance_tests_aks.yaml
vendored
1
.github/workflows/acceptance_tests_aks.yaml
vendored
|
|
@ -67,6 +67,7 @@ jobs:
|
|||
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
|
||||
run: |
|
||||
make testacc
|
||||
make frameworkacc
|
||||
- name: Destroy AKS
|
||||
if: always()
|
||||
working-directory: ${{ github.workspace }}/kubernetes/test-infra/aks
|
||||
|
|
|
|||
1
.github/workflows/acceptance_tests_eks.yaml
vendored
1
.github/workflows/acceptance_tests_eks.yaml
vendored
|
|
@ -85,6 +85,7 @@ jobs:
|
|||
# More information: https://developer.hashicorp.com/terraform/plugin/sdkv2/testing/acceptance-tests#terraform-cli-installation-behaviors
|
||||
run: |
|
||||
make testacc
|
||||
make frameworkacc
|
||||
- name: Destroy EKS cluster
|
||||
if: always() # we should destroy the cluster even if the tests fail
|
||||
working-directory: ${{ github.workspace }}/kubernetes/test-infra/eks
|
||||
|
|
|
|||
1
.github/workflows/acceptance_tests_gke.yaml
vendored
1
.github/workflows/acceptance_tests_gke.yaml
vendored
|
|
@ -85,6 +85,7 @@ jobs:
|
|||
# More information: https://developer.hashicorp.com/terraform/plugin/sdkv2/testing/acceptance-tests#terraform-cli-installation-behaviors
|
||||
run: |
|
||||
make testacc
|
||||
make frameworkacc
|
||||
- name: Destroy GKE cluster
|
||||
if: always() # we should destroy the cluster even if the tests fail
|
||||
working-directory: ${{ github.workspace }}/kubernetes/test-infra/gke
|
||||
|
|
|
|||
7
.github/workflows/acceptance_tests_kind.yaml
vendored
7
.github/workflows/acceptance_tests_kind.yaml
vendored
|
|
@ -11,7 +11,7 @@ on:
|
|||
default: "^TestAcc"
|
||||
terraformVersion:
|
||||
description: Terraform version
|
||||
default: 1.7.5
|
||||
default: 1.10.0-rc3 # FIXME update this once 1.10 goes out
|
||||
parallelRuns:
|
||||
description: The maximum number of tests to run simultaneously
|
||||
default: 8
|
||||
|
|
@ -29,7 +29,7 @@ env:
|
|||
KUBECONFIG: ${{ github.workspace }}/.kube/config
|
||||
KIND_VERSION: ${{ github.event.inputs.kindVersion || vars.KIND_VERSION || '0.25.0' }}
|
||||
PARALLEL_RUNS: ${{ github.event.inputs.parallelRuns || vars.PARALLEL_RUNS || '8' }}
|
||||
TERRAFORM_VERSION: ${{ github.event.inputs.terraformVersion || vars.TERRAFORM_VERSION || '1.9.2' }}
|
||||
TERRAFORM_VERSION: ${{ github.event.inputs.terraformVersion || vars.TERRAFORM_VERSION || '1.10.0-rc3' }}
|
||||
|
||||
jobs:
|
||||
acceptance_tests_kind:
|
||||
|
|
@ -71,7 +71,7 @@ jobs:
|
|||
- name: Install Terraform
|
||||
uses: hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36 # v3.0.0
|
||||
with:
|
||||
terraform_version: ${{ env.TERRAFORM_VERSION }}
|
||||
# terraform_version: ${{ env.TERRAFORM_VERSION }}
|
||||
terraform_wrapper: false
|
||||
- name: Setup kind
|
||||
uses: helm/kind-action@99576bfa6ddf9a8e612d83b513da5a75875caced # v1.9.0
|
||||
|
|
@ -90,3 +90,4 @@ jobs:
|
|||
# More information: https://developer.hashicorp.com/terraform/plugin/sdkv2/testing/acceptance-tests#terraform-cli-installation-behaviors
|
||||
run: |
|
||||
make testacc
|
||||
make frameworkacc
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ OS_ARCH := $(shell go env GOOS)_$(shell go env GOARCH)
|
|||
TF_PROV_DOCS := $(PWD)/kubernetes/test-infra/tfproviderdocs
|
||||
|
||||
PROVIDER_FUNCTIONS_DIR := "$(PROVIDER_DIR)/internal/framework/provider/functions"
|
||||
PROVIDER_FRAMEWORK_DIR := "$(PROVIDER_DIR)/internal/framework/provider/..."
|
||||
|
||||
ifneq ($(PWD),$(PROVIDER_DIR))
|
||||
$(error "Makefile must be run from the provider directory")
|
||||
|
|
@ -77,7 +78,10 @@ testacc: fmtcheck vet
|
|||
TF_ACC=1 go test $(TEST) -v -vet=off $(TESTARGS) -parallel $(PARALLEL_RUNS) -timeout 3h
|
||||
|
||||
testfuncs: fmtcheck
|
||||
go test $(PROVIDER_FUNCTIONS_DIR) -v -vet=off $(TESTARGS) -parallel $(PARALLEL_RUNS)
|
||||
go test $(PROVIDER_FUNCTIONS_DIR) -v -vet=off $(TESTARGS) -parallel $(PARALLEL_RUNS)
|
||||
|
||||
frameworkacc:
|
||||
TF_ACC=1 go test $(PROVIDER_FRAMEWORK_DIR) -v -vet=off $(TESTARGS) -parallel $(PARALLEL_RUNS)
|
||||
|
||||
test-compile:
|
||||
@if [ "$(TEST)" = "./..." ]; then \
|
||||
|
|
@ -175,4 +179,4 @@ docs-lint-fix: tools
|
|||
@echo "==> Fixing website terraform blocks code with terrafmt..."
|
||||
@terrafmt fmt ./docs --pattern '*.markdown'
|
||||
|
||||
.PHONY: build test testacc tools vet fmt fmtcheck terrafmt test-compile depscheck tests-lint tests-lint-fix docs-lint docs-lint-fix changelog changelog-entry
|
||||
.PHONY: build test testacc frameworkacc tools vet fmt fmtcheck terrafmt test-compile depscheck tests-lint tests-lint-fix docs-lint docs-lint-fix changelog changelog-entry
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
subcategory: "certificates/v1"
|
||||
page_title: "Kubernetes: kubernetes_certificate_signing_request_v1"
|
||||
description: |-
|
||||
Use this resource to generate TLS certificates using Kubernetes.
|
||||
---
|
||||
|
||||
# Ephemeral: kubernetes_certificate_signing_request_v1
|
||||
|
||||
Use this resource to generate TLS certificates using Kubernetes. This resource enables automation of [X.509](https://www.itu.int/rec/T-REC-X.509) credential provisioning (including TLS/SSL certificates). It does this by creating a CertificateSigningRequest using the Kubernetes API, which generates a certificate from the Certificate Authority (CA) configured in the Kubernetes cluster. The CSR can be approved automatically by Terraform, or it can be approved by a custom controller running in Kubernetes. See [Kubernetes reference](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/) for all available options pertaining to CertificateSigningRequests.
|
||||
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `metadata` (Block List, Min: 1, Max: 1) Standard certificate signing request's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata (see [below for nested schema](#nestedblock--metadata))
|
||||
- `spec` (Block List, Min: 1, Max: 1) CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued.
|
||||
|
||||
Kubelets use this API to obtain:
|
||||
1. client certificates to authenticate to kube-apiserver (with the "kubernetes.io/kube-apiserver-client-kubelet" signerName).
|
||||
2. serving certificates for TLS endpoints kube-apiserver can connect to securely (with the "kubernetes.io/kubelet-serving" signerName).
|
||||
|
||||
This API can be used to request client certificates to authenticate to kube-apiserver (with the "kubernetes.io/kube-apiserver-client" signerName), or to obtain certificates from custom non-Kubernetes signers. (see [below for nested schema](#nestedblock--spec))
|
||||
|
||||
### Optional
|
||||
|
||||
- `auto_approve` (Boolean) Automatically approve the CertificateSigningRequest
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `certificate` (String) certificate is populated with an issued certificate by the signer after an Approved condition is present. This field is set via the /status subresource. Once populated, this field is immutable.
|
||||
|
||||
If the certificate signing request is denied, a condition of type "Denied" is added and this field remains empty. If the signer cannot issue the certificate, a condition of type "Failed" is added and this field remains empty.
|
||||
|
||||
Validation requirements:
|
||||
1. certificate must contain one or more PEM blocks.
|
||||
2. All PEM blocks must have the "CERTIFICATE" label, contain no headers, and the encoded data
|
||||
must be a BER-encoded ASN.1 Certificate structure as described in section 4 of RFC5280.
|
||||
3. Non-PEM content may appear before or after the "CERTIFICATE" PEM blocks and is unvalidated,
|
||||
to allow for explanatory text as described in section 5.2 of RFC7468.
|
||||
|
||||
If more than one PEM block is present, and the definition of the requested spec.signerName does not indicate otherwise, the first block is the issued certificate, and subsequent blocks should be treated as intermediate certificates and presented in TLS handshakes.
|
||||
|
||||
The certificate is encoded in PEM format.
|
||||
|
||||
When serialized as JSON or YAML, the data is additionally base64-encoded, so it consists of:
|
||||
|
||||
base64(
|
||||
- `id` (String) The ID of this resource.
|
||||
|
||||
<a id="nestedblock--metadata"></a>
|
||||
### Nested Schema for `metadata`
|
||||
|
||||
Optional:
|
||||
|
||||
- `name` (String) Name of the certificate signing request, must be unique. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
|
||||
<a id="nestedblock--spec"></a>
|
||||
### Nested Schema for `spec`
|
||||
|
||||
Required:
|
||||
|
||||
- `request` (String) request contains an x509 certificate signing request encoded in a "CERTIFICATE REQUEST" PEM block. When serialized as JSON or YAML, the data is additionally base64-encoded.
|
||||
- `signer_name` (String) signerName indicates the requested signer, and is a qualified name.
|
||||
|
||||
List/watch requests for CertificateSigningRequests can filter on this field using a "spec.signerName=NAME" fieldSelector.
|
||||
|
||||
Well-known Kubernetes signers are:
|
||||
1. "kubernetes.io/kube-apiserver-client": issues client certificates that can be used to authenticate to kube-apiserver.
|
||||
Requests for this signer are never auto-approved by kube-controller-manager, can be issued by the "csrsigning" controller in kube-controller-manager.
|
||||
2. "kubernetes.io/kube-apiserver-client-kubelet": issues client certificates that kubelets use to authenticate to kube-apiserver.
|
||||
Requests for this signer can be auto-approved by the "csrapproving" controller in kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager.
|
||||
3. "kubernetes.io/kubelet-serving" issues serving certificates that kubelets use to serve TLS endpoints, which kube-apiserver can connect to securely.
|
||||
Requests for this signer are never auto-approved by kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager.
|
||||
|
||||
More details are available at https://k8s.io/docs/reference/access-authn-authz/certificate-signing-requests/#kubernetes-signers
|
||||
|
||||
Custom signerNames can also be specified. The signer defines:
|
||||
1. Trust distribution: how trust (CA bundles) are distributed.
|
||||
2. Permitted subjects: and behavior when a disallowed subject is requested.
|
||||
3. Required, permitted, or forbidden x509 extensions in the request (including whether subjectAltNames are allowed, which types, restrictions on allowed values) and behavior when a disallowed extension is requested.
|
||||
4. Required, permitted, or forbidden key usages / extended key usages.
|
||||
5. Expiration/certificate lifetime: whether it is fixed by the signer, configurable by the admin.
|
||||
6. Whether or not requests for CA certificates are allowed.
|
||||
|
||||
Optional:
|
||||
|
||||
- `expiration_seconds` (Integer) expirationSeconds is the requested duration of validity of the issued certificate.
|
||||
|
||||
The certificate signer may issue a certificate with a different validity duration so a client must check the delta between the notBefore and and notAfter fields in the issued certificate to determine the actual duration. The v1.22+ in-tree implementations of the well-known Kubernetes signers will honor this field as long as the requested duration is not greater than the maximum duration they will honor per the --cluster-signing-duration CLI flag to the Kubernetes controller manager.
|
||||
|
||||
Certificate signers may not honor this field for various reasons:
|
||||
|
||||
1. Old signer that is unaware of the field (such as the in-tree implementations prior to v1.22)
|
||||
2. Signer whose configured maximum is shorter than the requested duration
|
||||
3. Signer whose configured minimum is longer than the requested duration
|
||||
|
||||
The minimum valid value for expirationSeconds is 600, i.e. 10 minutes.
|
||||
|
||||
- `usages` (Set of String) usages specifies a set of key usages requested in the issued certificate.
|
||||
|
||||
Requests for TLS client certificates typically request: "digital signature", "key encipherment", "client auth".
|
||||
|
||||
Requests for TLS serving certificates typically request: "key encipherment", "digital signature", "server auth".
|
||||
|
||||
Valid values are:
|
||||
"signing", "digital signature", "content commitment",
|
||||
"key encipherment", "key agreement", "data encipherment",
|
||||
"cert sign", "crl sign", "encipher only", "decipher only", "any",
|
||||
"server auth", "client auth",
|
||||
"code signing", "email protection", "s/mime",
|
||||
"ipsec end system", "ipsec tunnel", "ipsec user",
|
||||
"timestamping", "ocsp signing", "microsoft sgc", "netscape sgc"
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
ephemeral "kubernetes_certificate_signing_request_v1" "example" {
|
||||
metadata {
|
||||
name = "example"
|
||||
}
|
||||
spec {
|
||||
usages = ["client auth", "server auth"]
|
||||
signer_name = "kubernetes.io/kube-apiserver-client"
|
||||
|
||||
request = <<EOT
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIHSMIGBAgEAMCoxGDAWBgNVBAoTD2V4YW1wbGUgY2x1c3RlcjEOMAwGA1UEAxMF
|
||||
YWRtaW4wTjAQBgcqhkjOPQIBBgUrgQQAIQM6AASSG8S2+hQvfMq5ucngPCzK0m0C
|
||||
ImigHcF787djpF2QDbz3oQ3QsM/I7ftdjB/HHlG2a5YpqjzT0KAAMAoGCCqGSM49
|
||||
BAMCA0AAMD0CHQDErNLjX86BVfOsYh/A4zmjmGknZpc2u6/coTHqAhxcR41hEU1I
|
||||
DpNPvh30e0Js8/DYn2YUfu/pQU19
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
EOT
|
||||
}
|
||||
|
||||
auto_approve = true
|
||||
}
|
||||
```
|
||||
|
||||
75
docs/ephemeral-resources/kubernetes_token_request_v1.md
Normal file
75
docs/ephemeral-resources/kubernetes_token_request_v1.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
subcategory: "authentication/v1"
|
||||
page_title: "Kubernetes: kubernetes_token_request_v1"
|
||||
description: |-
|
||||
TokenRequest requests a token for a given service account.
|
||||
---
|
||||
|
||||
# Ephemeral: kubernetes_token_request_v1
|
||||
|
||||
TokenRequest requests a token for a given service account.
|
||||
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- `metadata` (Block List, Min: 1, Max: 1) Standard token request's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata (see [below for nested schema](#nestedblock--metadata))
|
||||
|
||||
### Optional
|
||||
|
||||
- `spec` (Block List, Max: 1) (see [below for nested schema](#nestedblock--spec))
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `token` (String, Sensitive) Token is the opaque bearer token.
|
||||
|
||||
<a id="nestedblock--metadata"></a>
|
||||
### Nested Schema for `metadata`
|
||||
|
||||
Optional:
|
||||
|
||||
- `name` (String) Name of the token request, must be unique. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
- `namespace` (String) Namespace defines the space within which name of the token request must be unique.
|
||||
|
||||
<a id="nestedblock--spec"></a>
|
||||
### Nested Schema for `spec`
|
||||
|
||||
Optional:
|
||||
|
||||
- `audiences` (List of String) Audiences are the intendend audiences of the token. A recipient of a token must identify themself with an identifier in the list of audiences of the token, and otherwise should reject the token. A token issued for multiple audiences may be used to authenticate against any of the audiences listed but implies a high degree of trust between the target audiences.
|
||||
- `bound_object_ref` (Block List, Max: 1) BoundObjectRef is a reference to an object that the token will be bound to. The token will only be valid for as long as the bound object exists. NOTE: The API server's TokenReview endpoint will validate the BoundObjectRef, but other audiences may not. Keep ExpirationSeconds small if you want prompt revocation. (see [below for nested schema](#nestedblock--spec--bound_object_ref))
|
||||
- `expiration_seconds` (Number) expiration_seconds is the requested duration of validity of the request. The token issuer may return a token with a different validity duration so a client needs to check the 'expiration' field in a response. The expiration can't be less than 10 minutes.
|
||||
|
||||
<a id="nestedblock--spec--bound_object_ref"></a>
|
||||
### Nested Schema for `spec.bound_object_ref`
|
||||
|
||||
Optional:
|
||||
|
||||
- `api_version` (String) API version of the referent.
|
||||
- `kind` (String) Kind of the referent. Valid kinds are 'Pod' and 'Secret'.
|
||||
- `name` (String) Name of the referent.
|
||||
- `uid` (String) UID of the referent.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "kubernetes_service_account_v1" "test" {
|
||||
metadata {
|
||||
name = "test"
|
||||
}
|
||||
}
|
||||
|
||||
ephemeral "kubernetes_token_request_v1" "test" {
|
||||
metadata {
|
||||
name = kubernetes_service_account_v1.test.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
audiences = [
|
||||
"api",
|
||||
"vault",
|
||||
"factors"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
53
go.mod
53
go.mod
|
|
@ -1,31 +1,33 @@
|
|||
module github.com/hashicorp/terraform-provider-kubernetes
|
||||
|
||||
go 1.21
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.22.5
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/getkin/kin-openapi v0.111.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/hashicorp/go-hclog v1.6.3
|
||||
github.com/hashicorp/go-plugin v1.6.0
|
||||
github.com/hashicorp/go-version v1.6.0
|
||||
github.com/hashicorp/hc-install v0.6.4
|
||||
github.com/hashicorp/hcl/v2 v2.20.1
|
||||
github.com/hashicorp/go-plugin v1.6.2
|
||||
github.com/hashicorp/go-version v1.7.0
|
||||
github.com/hashicorp/hc-install v0.9.0
|
||||
github.com/hashicorp/hcl/v2 v2.23.0
|
||||
github.com/hashicorp/terraform-exec v0.21.0
|
||||
github.com/hashicorp/terraform-json v0.22.1
|
||||
github.com/hashicorp/terraform-json v0.23.0
|
||||
github.com/hashicorp/terraform-plugin-docs v0.16.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.7.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.23.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.13.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.25.0
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0
|
||||
github.com/hashicorp/terraform-plugin-mux v0.16.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.8.0
|
||||
github.com/hashicorp/terraform-plugin-mux v0.17.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.11.0
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/hashstructure v1.1.0
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
golang.org/x/mod v0.16.0
|
||||
github.com/stretchr/testify v1.8.3
|
||||
golang.org/x/mod v0.21.0
|
||||
k8s.io/api v0.28.6
|
||||
k8s.io/apiextensions-apiserver v0.28.6
|
||||
k8s.io/apimachinery v0.28.6
|
||||
|
|
@ -47,6 +49,7 @@ require (
|
|||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/invopop/yaml v0.2.0 // indirect
|
||||
github.com/mitchellh/cli v1.1.5 // indirect
|
||||
|
|
@ -59,9 +62,9 @@ require (
|
|||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
@ -123,18 +126,18 @@ require (
|
|||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4
|
||||
github.com/zclconf/go-cty v1.15.0
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/oauth2 v0.17.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/term v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/crypto v0.29.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/oauth2 v0.22.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/term v0.26.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/grpc v1.63.2
|
||||
google.golang.org/protobuf v1.34.0 // indirect
|
||||
google.golang.org/grpc v1.67.1
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
|||
102
go.sum
102
go.sum
|
|
@ -158,37 +158,39 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH
|
|||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A=
|
||||
github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI=
|
||||
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
|
||||
github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hc-install v0.6.4 h1:QLqlM56/+SIIGvGcfFiwMY3z5WGXT066suo/v9Km8e0=
|
||||
github.com/hashicorp/hc-install v0.6.4/go.mod h1:05LWLy8TD842OtgcfBbOT0WMoInBMUSHjmDx10zuBIA=
|
||||
github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc=
|
||||
github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hc-install v0.9.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE=
|
||||
github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg=
|
||||
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
|
||||
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
|
||||
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
|
||||
github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
|
||||
github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec=
|
||||
github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
|
||||
github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI=
|
||||
github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI=
|
||||
github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.7.0 h1:wOULbVmfONnJo9iq7/q+iBOBJul5vRovaYJIu2cY/Pw=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.7.0/go.mod h1:jY9Id+3KbZ17OMpulgnWLSfwxNVYSoYBQFTgsx044CI=
|
||||
github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co=
|
||||
github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU=
|
||||
github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks=
|
||||
github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw=
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
|
||||
github.com/hashicorp/terraform-plugin-mux v0.16.0 h1:RCzXHGDYwUwwqfYYWJKBFaS3fQsWn/ZECEiW7p2023I=
|
||||
github.com/hashicorp/terraform-plugin-mux v0.16.0/go.mod h1:PF79mAsPc8CpusXPfEVa4X8PtkB+ngWoiUClMrNZlYo=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.8.0 h1:wdYIgwDk4iO933gC4S8KbKdnMQShu6BXuZQPScmHvpk=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.8.0/go.mod h1:o2kOgf18ADUaZGhtOl0YCkfIxg01MAiMATT2EtIHlZk=
|
||||
github.com/hashicorp/terraform-plugin-mux v0.17.0 h1:/J3vv3Ps2ISkbLPiZOLspFcIZ0v5ycUXCEQScudGCCw=
|
||||
github.com/hashicorp/terraform-plugin-mux v0.17.0/go.mod h1:yWuM9U1Jg8DryNfvCp+lH70WcYv6D8aooQxxxIzFDsE=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 h1:wyKCCtn6pBBL46c1uIIBNUOWlNfYXfXpVo16iDyLp8Y=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0/go.mod h1:B0Al8NyYVr8Mp/KLwssKXG1RqnTk7FySqSn4fRuLNgw=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.11.0 h1:MeDT5W3YHbONJt2aPQyaBsgQeAIckwPX41EUHXEn29A=
|
||||
github.com/hashicorp/terraform-plugin-testing v1.11.0/go.mod h1:WNAHQ3DcgV/0J+B15WTE6hDvxcUdkPPpnB1FR3M910U=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
|
||||
|
|
@ -333,8 +335,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
|
|
@ -349,10 +351,10 @@ github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd
|
|||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
|
||||
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
|
||||
github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
|
||||
github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
|
@ -362,8 +364,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U=
|
||||
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
|
|
@ -373,8 +375,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -386,19 +388,19 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
|
||||
golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
|
||||
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
|
||||
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -417,22 +419,22 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
@ -444,8 +446,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
|
||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
@ -457,13 +459,13 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ
|
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
|
||||
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
||||
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
|
||||
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
|
@ -474,8 +476,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4=
|
||||
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
|
||||
package authenticationv1_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/echoprovider"
|
||||
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/internal/framework/provider"
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/kubernetes"
|
||||
|
||||
sdkv2 "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
)
|
||||
|
||||
// NOTE this is a shim back to the SDKv2 so we don't have to duplicate
|
||||
// the client initialization code.
|
||||
func sdkv2providerMeta() func() any {
|
||||
p := kubernetes.Provider()
|
||||
p.Configure(context.Background(), sdkv2.NewResourceConfigRaw(nil))
|
||||
return p.Meta
|
||||
}
|
||||
|
||||
var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"kubernetes": providerserver.NewProtocol6WithError(provider.New("test", sdkv2providerMeta())),
|
||||
"echo": echoprovider.NewProviderServer(),
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
|
||||
package authenticationv1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
|
||||
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/kubernetes"
|
||||
|
||||
authv1 "k8s.io/api/authentication/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var (
|
||||
_ ephemeral.EphemeralResource = (*TokenRequestEphemeralResource)(nil)
|
||||
_ ephemeral.EphemeralResourceWithConfigure = (*TokenRequestEphemeralResource)(nil)
|
||||
)
|
||||
|
||||
type TokenRequestEphemeralResource struct {
|
||||
SDKv2Meta func() any
|
||||
}
|
||||
|
||||
type TokenRequestMetadata struct {
|
||||
Name types.String `tfsdk:"name"`
|
||||
Namespace types.String `tfsdk:"namespace"`
|
||||
}
|
||||
|
||||
type BoundObjectReference struct {
|
||||
APIVersion types.String `tfsdk:"api_version"`
|
||||
Kind types.String `tfsdk:"kind"`
|
||||
Name types.String `tfsdk:"name"`
|
||||
UID types.String `tfsdk:"uid"`
|
||||
}
|
||||
|
||||
type TokenRequestSpec struct {
|
||||
Audiences []types.String `tfsdk:"audiences"`
|
||||
BoundObjecRef *BoundObjectReference `tfsdk:"bound_object_ref"`
|
||||
ExpirationSeconds types.Int64 `tfsdk:"expiration_seconds"`
|
||||
}
|
||||
|
||||
type TokenRequestModel struct {
|
||||
Metadata TokenRequestMetadata `tfsdk:"metadata"`
|
||||
Spec *TokenRequestSpec `tfsdk:"spec"`
|
||||
|
||||
Token types.String `tfsdk:"token"`
|
||||
ExpirationTimestamp types.String `tfsdk:"expiration_timestamp"`
|
||||
}
|
||||
|
||||
func NewTokenRequestEphemeralResource() ephemeral.EphemeralResource {
|
||||
return &TokenRequestEphemeralResource{}
|
||||
}
|
||||
|
||||
func (r *TokenRequestEphemeralResource) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.SDKv2Meta = req.ProviderData.(func() any)
|
||||
}
|
||||
|
||||
func (r *TokenRequestEphemeralResource) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_token_request_v1"
|
||||
}
|
||||
|
||||
func (r *TokenRequestEphemeralResource) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) {
|
||||
objectMetaOpenAPI := metav1.ObjectMeta{}.SwaggerDoc()
|
||||
|
||||
tokenreqOpenAPISpec := authv1.TokenRequestSpec{}.SwaggerDoc()
|
||||
tokenreqOpenAPIStatus := authv1.TokenRequestStatus{}.SwaggerDoc()
|
||||
tokenreqOpenAPIBoundObjRef := authv1.BoundObjectReference{}.SwaggerDoc()
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "TokenRequest requests a token for a given service account.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"token": schema.StringAttribute{
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
Description: tokenreqOpenAPIStatus["token"],
|
||||
},
|
||||
"expiration_timestamp": schema.StringAttribute{
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
Description: tokenreqOpenAPIStatus["expirationTimestamp"],
|
||||
},
|
||||
},
|
||||
Blocks: map[string]schema.Block{
|
||||
"metadata": schema.SingleNestedBlock{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"name": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: objectMetaOpenAPI["name"],
|
||||
},
|
||||
"namespace": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: objectMetaOpenAPI["namespace"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"spec": schema.SingleNestedBlock{
|
||||
Description: tokenreqOpenAPISpec[""],
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"audiences": schema.ListAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ElementType: types.StringType,
|
||||
Description: tokenreqOpenAPISpec["audiences"],
|
||||
},
|
||||
"expiration_seconds": schema.Int64Attribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: tokenreqOpenAPISpec["expirationSeconds"],
|
||||
},
|
||||
},
|
||||
Blocks: map[string]schema.Block{
|
||||
"bound_object_ref": schema.SingleNestedBlock{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"api_version": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Description: tokenreqOpenAPIBoundObjRef["apiVersion"],
|
||||
},
|
||||
"kind": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Description: tokenreqOpenAPIBoundObjRef["kind"],
|
||||
},
|
||||
"name": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Description: tokenreqOpenAPIBoundObjRef["name"],
|
||||
},
|
||||
"uid": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Description: tokenreqOpenAPIBoundObjRef["uid"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func expandStringSlice(s []types.String) []string {
|
||||
ss := make([]string, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
ss[i] = s[i].ValueString()
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
func (r *TokenRequestEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
|
||||
var data TokenRequestModel
|
||||
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
name := data.Metadata.Name.ValueString()
|
||||
namespace := data.Metadata.Namespace.ValueString()
|
||||
if namespace == "" {
|
||||
namespace = "default"
|
||||
}
|
||||
|
||||
conn, err := r.SDKv2Meta().(kubernetes.KubeClientsets).MainClientset()
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("error initializing kubernetes client", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tokenRequest := authv1.TokenRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
|
||||
if data.Spec != nil {
|
||||
tokenRequest.Spec = authv1.TokenRequestSpec{
|
||||
Audiences: expandStringSlice(data.Spec.Audiences),
|
||||
ExpirationSeconds: data.Spec.ExpirationSeconds.ValueInt64Pointer(),
|
||||
}
|
||||
|
||||
if data.Spec.BoundObjecRef != nil {
|
||||
tokenRequest.Spec.BoundObjectRef = &authv1.BoundObjectReference{
|
||||
Kind: data.Spec.BoundObjecRef.Kind.ValueString(),
|
||||
APIVersion: data.Spec.BoundObjecRef.APIVersion.ValueString(),
|
||||
Name: data.Spec.BoundObjecRef.Name.ValueString(),
|
||||
UID: k8stypes.UID(data.Spec.BoundObjecRef.UID.ValueString()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res, err := conn.CoreV1().ServiceAccounts(namespace).CreateToken(ctx, name, &tokenRequest, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("error creating token request", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
data.ExpirationTimestamp = types.StringValue(res.Status.ExpirationTimestamp.Format(time.RFC3339))
|
||||
data.Token = types.StringValue(res.Status.Token)
|
||||
|
||||
resp.Diagnostics.Append(resp.Result.Set(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
|
||||
package authenticationv1_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
|
||||
"github.com/hashicorp/terraform-plugin-testing/statecheck"
|
||||
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
|
||||
)
|
||||
|
||||
func TestAccEpehemeralTokenRequest_basic(t *testing.T) {
|
||||
name := "default"
|
||||
namespace := "default"
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testEphemeralTokenRequestV1Config(name, namespace),
|
||||
ConfigStateChecks: []statecheck.StateCheck{
|
||||
statecheck.ExpectKnownValue(
|
||||
"echo.test",
|
||||
tfjsonpath.New("data").AtMapKey("token"),
|
||||
knownvalue.NotNull(),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testEphemeralTokenRequestV1Config(name, namespace string) string {
|
||||
return fmt.Sprintf(`
|
||||
ephemeral "kubernetes_token_request_v1" "test" {
|
||||
metadata {
|
||||
name = %q
|
||||
namespace = %q
|
||||
}
|
||||
spec {
|
||||
audiences = ["api", "vault"]
|
||||
}
|
||||
}
|
||||
|
||||
provider "echo" {
|
||||
data = ephemeral.kubernetes_token_request_v1.test
|
||||
}
|
||||
|
||||
resource "echo" "test" {}`, name, namespace)
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
|
||||
package certificatesv1_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/echoprovider"
|
||||
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/internal/framework/provider"
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/kubernetes"
|
||||
|
||||
sdkv2 "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
)
|
||||
|
||||
// NOTE this is a shim back to the SDKv2 so we don't have to duplicate
|
||||
// the client initialization code.
|
||||
func sdkv2providerMeta() func() any {
|
||||
p := kubernetes.Provider()
|
||||
p.Configure(context.Background(), sdkv2.NewResourceConfigRaw(nil))
|
||||
return p.Meta
|
||||
}
|
||||
|
||||
var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"kubernetes": providerserver.NewProtocol6WithError(provider.New("test", sdkv2providerMeta())),
|
||||
"echo": echoprovider.NewProviderServer(),
|
||||
}
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
|
||||
package certificatesv1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
|
||||
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/kubernetes"
|
||||
|
||||
certificatesv1 "k8s.io/api/certificates/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
kwait "k8s.io/apimachinery/pkg/util/wait"
|
||||
kretry "k8s.io/client-go/util/retry"
|
||||
)
|
||||
|
||||
var (
|
||||
_ ephemeral.EphemeralResource = (*CertificateSigningRequestEphemeralResource)(nil)
|
||||
_ ephemeral.EphemeralResourceWithConfigure = (*CertificateSigningRequestEphemeralResource)(nil)
|
||||
)
|
||||
|
||||
type CertificateSigningRequestEphemeralResource struct {
|
||||
SDKv2Meta func() any
|
||||
}
|
||||
|
||||
type CertificateSigningRequestMetadata struct {
|
||||
Name types.String `tfsdk:"name"`
|
||||
}
|
||||
|
||||
type CertificateSigningRequestSpec struct {
|
||||
ExpirationSeconds types.Int32 `tfsdk:"expiration_seconds"`
|
||||
Request types.String `tfsdk:"request"`
|
||||
SignerName types.String `tfsdk:"signer_name"`
|
||||
Usages []types.String `tfsdk:"usages"`
|
||||
}
|
||||
|
||||
type CertificateSigningRequestModel struct {
|
||||
Metadata CertificateSigningRequestMetadata `tfsdk:"metadata"`
|
||||
Spec CertificateSigningRequestSpec `tfsdk:"spec"`
|
||||
|
||||
AutoApprove types.Bool `tfsdk:"auto_approve"`
|
||||
Certificate types.String `tfsdk:"certificate"`
|
||||
}
|
||||
|
||||
func NewCertificateSigningRequestEphemeralResource() ephemeral.EphemeralResource {
|
||||
return &CertificateSigningRequestEphemeralResource{}
|
||||
}
|
||||
|
||||
func (r *CertificateSigningRequestEphemeralResource) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.SDKv2Meta = req.ProviderData.(func() any)
|
||||
}
|
||||
|
||||
func (r *CertificateSigningRequestEphemeralResource) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_certificate_signing_request_v1"
|
||||
}
|
||||
|
||||
func (r *CertificateSigningRequestEphemeralResource) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) {
|
||||
objectMetaOpenAPI := metav1.ObjectMeta{}.SwaggerDoc()
|
||||
csrOpenAPI := certificatesv1.CertificateSigningRequest{}.SwaggerDoc()
|
||||
csrOpenAPISpec := certificatesv1.CertificateSigningRequestSpec{}.SwaggerDoc()
|
||||
csrOpenAPIStatus := certificatesv1.CertificateSigningRequestStatus{}.SwaggerDoc()
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "TokenRequest requests a token for a given service account.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"auto_approve": schema.BoolAttribute{
|
||||
Description: "Automatically approve the Certificate Signing Request",
|
||||
Optional: true,
|
||||
},
|
||||
"certificate": schema.StringAttribute{
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
Description: csrOpenAPIStatus["certificate"],
|
||||
},
|
||||
},
|
||||
Blocks: map[string]schema.Block{
|
||||
"metadata": schema.SingleNestedBlock{
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"name": schema.StringAttribute{
|
||||
Required: true,
|
||||
Description: objectMetaOpenAPI["name"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"spec": schema.SingleNestedBlock{
|
||||
Description: csrOpenAPI[""],
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"usages": schema.ListAttribute{
|
||||
Description: csrOpenAPISpec["usages"],
|
||||
Optional: true,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"expiration_seconds": schema.Int32Attribute{
|
||||
Description: csrOpenAPISpec["expirationSeconds"],
|
||||
Optional: true,
|
||||
},
|
||||
"request": schema.StringAttribute{
|
||||
Description: csrOpenAPISpec["request"],
|
||||
Required: true,
|
||||
},
|
||||
"signer_name": schema.StringAttribute{
|
||||
Description: csrOpenAPISpec["signerName"],
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func expandUsages(s []types.String) []certificatesv1.KeyUsage {
|
||||
ss := make([]certificatesv1.KeyUsage, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
ss[i] = certificatesv1.KeyUsage(s[i].ValueString())
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
const (
|
||||
TerraformAutoApproveReason = "TerraformAutoApprove"
|
||||
TerraformAutoApproveMessage = "This CertificateSigningRequest was auto-approved by Terraform"
|
||||
)
|
||||
|
||||
func (r *CertificateSigningRequestEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
|
||||
var data CertificateSigningRequestModel
|
||||
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
name := data.Metadata.Name.ValueString()
|
||||
conn, err := r.SDKv2Meta().(kubernetes.KubeClientsets).MainClientset()
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("error setting up kubernetes client", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
csr := certificatesv1.CertificateSigningRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: certificatesv1.CertificateSigningRequestSpec{
|
||||
ExpirationSeconds: data.Spec.ExpirationSeconds.ValueInt32Pointer(),
|
||||
Request: []byte(data.Spec.Request.ValueString()),
|
||||
SignerName: data.Spec.SignerName.ValueString(),
|
||||
Usages: expandUsages(data.Spec.Usages),
|
||||
},
|
||||
}
|
||||
newcsr, err := conn.CertificatesV1().CertificateSigningRequests().Create(
|
||||
ctx, &csr, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("error creating CSR", err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.CertificatesV1().CertificateSigningRequests().Delete(
|
||||
ctx, csr.GetName(), metav1.DeleteOptions{})
|
||||
|
||||
// auto approve the certificate
|
||||
if data.AutoApprove.IsNull() || data.AutoApprove.ValueBool() {
|
||||
err := kretry.RetryOnConflict(kretry.DefaultRetry, func() error {
|
||||
pendingCSR, err := conn.CertificatesV1().CertificateSigningRequests().Get(
|
||||
ctx, newcsr.GetName(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
approval := certificatesv1.CertificateSigningRequestCondition{
|
||||
Status: corev1.ConditionTrue,
|
||||
Type: certificatesv1.CertificateApproved,
|
||||
Reason: TerraformAutoApproveReason,
|
||||
Message: TerraformAutoApproveMessage,
|
||||
}
|
||||
pendingCSR.Status.Certificate = []byte{}
|
||||
pendingCSR.Status.Conditions = append(pendingCSR.Status.Conditions, approval)
|
||||
_, err = conn.CertificatesV1().CertificateSigningRequests().UpdateApproval(
|
||||
ctx, newcsr.GetName(), pendingCSR, metav1.UpdateOptions{})
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("CSR auto approval failed", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// wait for the certificate to be issued
|
||||
waitingErr := fmt.Errorf("timed out waiting for certificate")
|
||||
waitForIssue := kwait.Backoff{
|
||||
Steps: 10,
|
||||
Duration: 5 * time.Second,
|
||||
Factor: 1.5,
|
||||
Jitter: 0.1,
|
||||
}
|
||||
err = kretry.OnError(waitForIssue, func(e error) bool { return e == waitingErr }, func() error {
|
||||
out, err := conn.CertificatesV1().CertificateSigningRequests().Get(ctx,
|
||||
newcsr.GetName(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, condition := range out.Status.Conditions {
|
||||
if condition.Type == certificatesv1.CertificateApproved &&
|
||||
len(out.Status.Certificate) > 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return waitingErr
|
||||
})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("error waiting for certificate to be issued", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
issued, err := conn.CertificatesV1().CertificateSigningRequests().Get(ctx, newcsr.GetName(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("error getting CSR", err.Error())
|
||||
return
|
||||
}
|
||||
data.Certificate = types.StringValue(string(issued.Status.Certificate))
|
||||
|
||||
resp.Diagnostics.Append(resp.Result.Set(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
|
||||
package certificatesv1_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
|
||||
"github.com/hashicorp/terraform-plugin-testing/statecheck"
|
||||
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
|
||||
)
|
||||
|
||||
func TestAccEpehemeralCertificateSigningRequest_basic(t *testing.T) {
|
||||
name := "test"
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testEphemeralCertificateSigningRequestRequestV1Config(name),
|
||||
ConfigStateChecks: []statecheck.StateCheck{
|
||||
statecheck.ExpectKnownValue(
|
||||
"echo.test",
|
||||
tfjsonpath.New("data").AtMapKey("certificate"),
|
||||
knownvalue.NotNull(),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testEphemeralCertificateSigningRequestRequestV1Config(name string) string {
|
||||
return fmt.Sprintf(`
|
||||
ephemeral "kubernetes_certificate_signing_request_v1" "test" {
|
||||
metadata {
|
||||
name = %q
|
||||
}
|
||||
spec {
|
||||
request = <<EOT
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIHSMIGBAgEAMCoxGDAWBgNVBAoTD2V4YW1wbGUgY2x1c3RlcjEOMAwGA1UEAxMF
|
||||
YWRtaW4wTjAQBgcqhkjOPQIBBgUrgQQAIQM6AASSG8S2+hQvfMq5ucngPCzK0m0C
|
||||
ImigHcF787djpF2QDbz3oQ3QsM/I7ftdjB/HHlG2a5YpqjzT0KAAMAoGCCqGSM49
|
||||
BAMCA0AAMD0CHQDErNLjX86BVfOsYh/A4zmjmGknZpc2u6/coTHqAhxcR41hEU1I
|
||||
DpNPvh30e0Js8/DYn2YUfu/pQU19
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
EOT
|
||||
usages = ["client auth"]
|
||||
signer_name = "kubernetes.io/kube-apiserver-client"
|
||||
}
|
||||
auto_approve = true
|
||||
}
|
||||
|
||||
provider "echo" {
|
||||
data = ephemeral.kubernetes_certificate_signing_request_v1.test
|
||||
}
|
||||
|
||||
resource "echo" "test" {}`, name)
|
||||
}
|
||||
|
|
@ -10,5 +10,5 @@ import (
|
|||
)
|
||||
|
||||
var testAccProtoV5ProviderFactories = map[string]func() (tfprotov5.ProviderServer, error){
|
||||
"kubernetes": providerserver.NewProtocol5WithError(provider.New("test")),
|
||||
"kubernetes": providerserver.NewProtocol5WithError(provider.New("test", nil)),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,18 +7,22 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
|
||||
"github.com/hashicorp/terraform-plugin-framework/function"
|
||||
"github.com/hashicorp/terraform-plugin-framework/provider"
|
||||
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/internal/framework/provider/authenticationv1"
|
||||
"github.com/hashicorp/terraform-provider-kubernetes/internal/framework/provider/certificatesv1"
|
||||
pfunctions "github.com/hashicorp/terraform-provider-kubernetes/internal/framework/provider/functions"
|
||||
)
|
||||
|
||||
// Ensure KubernetesProvider satisfies various provider interfaces.
|
||||
var (
|
||||
_ provider.Provider = &KubernetesProvider{}
|
||||
_ provider.ProviderWithFunctions = &KubernetesProvider{}
|
||||
_ provider.Provider = &KubernetesProvider{}
|
||||
_ provider.ProviderWithFunctions = &KubernetesProvider{}
|
||||
_ provider.ProviderWithEphemeralResources = &KubernetesProvider{}
|
||||
)
|
||||
|
||||
// KubernetesProvider defines the provider implementation.
|
||||
|
|
@ -27,6 +31,9 @@ type KubernetesProvider struct {
|
|||
// provider is built and ran locally, and "test" when running acceptance
|
||||
// testing.
|
||||
version string
|
||||
|
||||
// SDKv2Meta is a function which returns provider meta struct from the SDKv2 code
|
||||
SDKv2Meta func() any
|
||||
}
|
||||
|
||||
// KubernetesProviderModel describes the provider data model.
|
||||
|
|
@ -192,6 +199,13 @@ func (p *KubernetesProvider) DataSources(ctx context.Context) []func() datasourc
|
|||
return []func() datasource.DataSource{}
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) EphemeralResources(ctx context.Context) []func() ephemeral.EphemeralResource {
|
||||
return []func() ephemeral.EphemeralResource{
|
||||
authenticationv1.NewTokenRequestEphemeralResource,
|
||||
certificatesv1.NewCertificateSigningRequestEphemeralResource,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *KubernetesProvider) Functions(ctx context.Context) []func() function.Function {
|
||||
return []func() function.Function{
|
||||
pfunctions.NewManifestDecodeFunction,
|
||||
|
|
@ -200,8 +214,9 @@ func (p *KubernetesProvider) Functions(ctx context.Context) []func() function.Fu
|
|||
}
|
||||
}
|
||||
|
||||
func New(version string) provider.Provider {
|
||||
func New(version string, sdkv2Meta func() any) provider.Provider {
|
||||
return &KubernetesProvider{
|
||||
version: version,
|
||||
version: version,
|
||||
SDKv2Meta: sdkv2Meta,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,157 +4,19 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/provider"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
apimachineryschema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
func (p *KubernetesProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
|
||||
var data KubernetesProviderModel
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
// NOTE for migration purposes we are re-using the client configurations which are initialized at configure time
|
||||
// by the SDKv2 codebase. Once all SDKv2 resources have been removed the client initialization code should be
|
||||
// migrated here.
|
||||
|
||||
_, err := newKubernetesClientConfig(ctx, data)
|
||||
if err != nil {
|
||||
resp.Diagnostics.Append(diag.NewErrorDiagnostic("failed to initilize Kubernetes client configuration", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
func newKubernetesClientConfig(ctx context.Context, data KubernetesProviderModel) (*restclient.Config, error) {
|
||||
overrides := &clientcmd.ConfigOverrides{}
|
||||
loader := &clientcmd.ClientConfigLoadingRules{}
|
||||
|
||||
configPaths := []string{}
|
||||
if v := data.ConfigPath.ValueString(); v != "" {
|
||||
configPaths = []string{v}
|
||||
} else if len(data.ConfigPaths) > 0 {
|
||||
for _, p := range data.ConfigPaths {
|
||||
configPaths = append(configPaths, p.ValueString())
|
||||
}
|
||||
} else if v := os.Getenv("KUBE_CONFIG_PATHS"); v != "" {
|
||||
configPaths = filepath.SplitList(v)
|
||||
}
|
||||
|
||||
if len(configPaths) > 0 {
|
||||
expandedPaths := []string{}
|
||||
for _, p := range configPaths {
|
||||
path, err := homedir.Expand(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tflog.Debug(ctx, "Using kubeconfig file", map[string]interface{}{"path": path})
|
||||
expandedPaths = append(expandedPaths, path)
|
||||
}
|
||||
if len(expandedPaths) == 1 {
|
||||
loader.ExplicitPath = expandedPaths[0]
|
||||
} else {
|
||||
loader.Precedence = expandedPaths
|
||||
}
|
||||
|
||||
ctxSuffix := "; default context"
|
||||
|
||||
kubectx := data.ConfigContext.ValueString()
|
||||
authInfo := data.ConfigContextAuthInfo.ValueString()
|
||||
cluster := data.ConfigContextCluster.ValueString()
|
||||
if kubectx != "" || authInfo != "" || cluster != "" {
|
||||
ctxSuffix = "; overridden context"
|
||||
if kubectx != "" {
|
||||
overrides.CurrentContext = kubectx
|
||||
ctxSuffix += fmt.Sprintf("; config ctx: %s", overrides.CurrentContext)
|
||||
tflog.Debug(ctx, "Using custom current context", map[string]interface{}{"context": overrides.CurrentContext})
|
||||
}
|
||||
|
||||
overrides.Context = clientcmdapi.Context{}
|
||||
if authInfo != "" {
|
||||
overrides.Context.AuthInfo = authInfo
|
||||
ctxSuffix += fmt.Sprintf("; auth_info: %s", overrides.Context.AuthInfo)
|
||||
}
|
||||
if cluster != "" {
|
||||
overrides.Context.Cluster = cluster
|
||||
ctxSuffix += fmt.Sprintf("; cluster: %s", overrides.Context.Cluster)
|
||||
}
|
||||
tflog.Debug(ctx, "Using overridden context", map[string]interface{}{"context": overrides.Context})
|
||||
}
|
||||
}
|
||||
|
||||
// Overriding with static configuration
|
||||
overrides.ClusterInfo.InsecureSkipTLSVerify = data.Insecure.ValueBool()
|
||||
overrides.ClusterInfo.TLSServerName = data.TLSServerName.ValueString()
|
||||
overrides.ClusterInfo.CertificateAuthorityData = bytes.NewBufferString(data.ClusterCACertificate.ValueString()).Bytes()
|
||||
overrides.AuthInfo.ClientCertificateData = bytes.NewBufferString(data.ClientCertificate.ValueString()).Bytes()
|
||||
|
||||
if v := data.Host.ValueString(); v != "" {
|
||||
// Server has to be the complete address of the kubernetes cluster (scheme://hostname:port), not just the hostname,
|
||||
// because `overrides` are processed too late to be taken into account by `defaultServerUrlFor()`.
|
||||
// This basically replicates what defaultServerUrlFor() does with config but for overrides,
|
||||
// see https://github.com/kubernetes/client-go/blob/v12.0.0/rest/url_utils.go#L85-L87
|
||||
hasCA := len(overrides.ClusterInfo.CertificateAuthorityData) != 0
|
||||
hasCert := len(overrides.AuthInfo.ClientCertificateData) != 0
|
||||
defaultTLS := hasCA || hasCert || overrides.ClusterInfo.InsecureSkipTLSVerify
|
||||
host, _, err := restclient.DefaultServerURL(v, "", apimachineryschema.GroupVersion{}, defaultTLS)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse host: %s", err)
|
||||
}
|
||||
|
||||
overrides.ClusterInfo.Server = host.String()
|
||||
}
|
||||
|
||||
overrides.AuthInfo.Username = data.Username.ValueString()
|
||||
overrides.AuthInfo.Password = data.Password.ValueString()
|
||||
overrides.AuthInfo.ClientKeyData = bytes.NewBufferString(data.ClientKey.ValueString()).Bytes()
|
||||
overrides.AuthInfo.Token = data.Token.ValueString()
|
||||
|
||||
overrides.ClusterDefaults.ProxyURL = data.ProxyURL.ValueString()
|
||||
|
||||
if len(data.Exec) > 0 {
|
||||
execData := data.Exec[0]
|
||||
|
||||
exec := &clientcmdapi.ExecConfig{}
|
||||
exec.InteractiveMode = clientcmdapi.IfAvailableExecInteractiveMode
|
||||
exec.APIVersion = execData.APIVersion.ValueString()
|
||||
exec.Command = execData.Command.ValueString()
|
||||
exec.Args = expandStringSlice(execData.Args)
|
||||
for kk, vv := range execData.Env {
|
||||
exec.Env = append(exec.Env, clientcmdapi.ExecEnvVar{Name: kk, Value: vv.ValueString()})
|
||||
}
|
||||
|
||||
overrides.AuthInfo.Exec = exec
|
||||
}
|
||||
|
||||
cc := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loader, overrides)
|
||||
cfg, err := cc.ClientConfig()
|
||||
if err != nil {
|
||||
tflog.Warn(ctx, "Invalid provider configuration was supplied. Provider operations likely to fail", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return nil, nil
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func expandStringSlice(s []types.String) []string {
|
||||
v := []string{}
|
||||
for _, vv := range s {
|
||||
v = append(v, vv.ValueString())
|
||||
}
|
||||
return v
|
||||
resp.ResourceData = p.SDKv2Meta
|
||||
resp.DataSourceData = p.SDKv2Meta
|
||||
resp.EphemeralResourceData = p.SDKv2Meta
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
||||
)
|
||||
|
||||
// testAccProtoV6ProviderFactories are used to instantiate a provider during
|
||||
// acceptance testing. The factory function will be invoked for every Terraform
|
||||
// CLI command executed to create a provider server to which the CLI can
|
||||
// reattach.
|
||||
var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"kubernetes": providerserver.NewProtocol6WithError(New("test")),
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
// You can add code here to run prior to any test case execution, for example assertions
|
||||
// about the appropriate environment variables being set are common to see in a pre-check
|
||||
// function.
|
||||
}
|
||||
|
|
@ -15,10 +15,12 @@ import (
|
|||
)
|
||||
|
||||
func MuxServer(ctx context.Context, v string) (tfprotov5.ProviderServer, error) {
|
||||
kubernetesProvider := kubernetes.Provider()
|
||||
|
||||
providers := []func() tfprotov5.ProviderServer{
|
||||
kubernetes.Provider().GRPCProvider,
|
||||
kubernetesProvider.GRPCProvider,
|
||||
manifest.Provider(),
|
||||
providerserver.NewProtocol5(framework.New(v)),
|
||||
providerserver.NewProtocol5(framework.New(v, kubernetesProvider.Meta)),
|
||||
}
|
||||
|
||||
return tf5muxserver.NewMuxServer(ctx, providers...)
|
||||
|
|
|
|||
Loading…
Reference in a new issue