0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-30 02:31:10 +00:00

feat: add min-tls option to provider config (#931)

* feat: add min-tls option to provider config

Signed-off-by: Robert Kaussow <mail@thegeeklab.de>

* fix: clenup code and add min-tls to file resource

Signed-off-by: Robert Kaussow <mail@thegeeklab.de>

* fix: linter errors, wrong schema type in file resource

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>

* chore: update docs

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>

---------

Signed-off-by: Robert Kaussow <mail@thegeeklab.de>
Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
Co-authored-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Robert Kaussow 2024-01-20 02:26:14 +01:00 committed by GitHub
parent 7d94bf73ec
commit 01ff2cb7db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 82 additions and 10 deletions

View File

@ -21,10 +21,10 @@ provider "proxmox" {
password = "the-password-set-during-installation-of-proxmox-ve"
# because self-signed TLS certificate is in use
insecure = true
# uncoment (unless on Windows...)
# uncomment (unless on Windows...)
# tmp_dir = "/var/tmp"
ssh {
ssh {
agent = true
# TODO: uncomment and configure if using api_token instead of password
# username = "root"
@ -121,9 +121,9 @@ In order to make the SSH connection, the provider needs to be able to resolve th
The following methods are used to resolve the node name, in the specified order:
1. Enumerate the node's network interfaces via the Proxmox API, and identify the first interface that:
1. Has an IPv4 address with IPv4 gateway configured, or
2. Has an IPv6 address with IPv6 gateway configured, or
3. Has an IPv4 address
1. Has an IPv4 address with IPv4 gateway configured, or
2. Has an IPv6 address with IPv6 gateway configured, or
3. Has an IPv4 address
2. Resolve the Proxmox node name (usually a shortname) via DNS using the system DNS resolver of the machine running Terraform.
In some cases this may not be the desired behavior, for example, when the node has multiple network interfaces, and the one that should be used for SSH is not the first one.
@ -222,6 +222,7 @@ In addition to [generic provider arguments](https://www.terraform.io/docs/config
- `endpoint` - (Required) The endpoint for the Proxmox Virtual Environment API (can also be sourced from `PROXMOX_VE_ENDPOINT`). Usually this is `https://<your-cluster-endpoint>:8006/`. **Do not** include `/api2/json` at the end.
- `insecure` - (Optional) Whether to skip the TLS verification step (can also be sourced from `PROXMOX_VE_INSECURE`). If omitted, defaults to `false`.
- `min_tls` - (Optional) The minimum required TLS version for API calls (can also be sourced from `PROXMOX_VE_MIN_TLS`). Supported values: `1.0|1.1|1.2|1.3`. If omitted, defaults to `1.3`.
- `otp` - (Optional, Deprecated) The one-time password for the Proxmox Virtual Environment API (can also be sourced from `PROXMOX_VE_OTP`).
- `password` - (Required) The password for the Proxmox Virtual Environment API (can also be sourced from `PROXMOX_VE_PASSWORD`).
- `username` - (Required) The username and realm for the Proxmox Virtual Environment API (can also be sourced from `PROXMOX_VE_USERNAME`). For example, `root@pam`.

View File

@ -117,6 +117,7 @@ resource "proxmox_virtual_environment_file" "ubuntu_container_template" {
when the source file is a URL referencing a `.qcow2` image.
- `insecure` - (Optional) Whether to skip the TLS verification step for
HTTPS sources (defaults to `false`).
- `min_tls` - (Optional) The minimum required TLS version for HTTPS sources. "Supported values: `1.0|1.1|1.2|1.3` (defaults to `1.3`).
- `path` - (Required) A path to a local file or a URL.
- `source_raw` - (Optional) The raw source (conflicts with `source_file`).
- `data` - (Required) The raw data.

View File

@ -56,6 +56,7 @@ type proxmoxProviderModel struct {
APIToken types.String `tfsdk:"api_token"`
Endpoint types.String `tfsdk:"endpoint"`
Insecure types.Bool `tfsdk:"insecure"`
MinTLS types.String `tfsdk:"min_tls"`
OTP types.String `tfsdk:"otp"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
@ -106,6 +107,11 @@ func (p *proxmoxProvider) Schema(_ context.Context, _ provider.SchemaRequest, re
Description: "Whether to skip the TLS verification step.",
Optional: true,
},
"min_tls": schema.StringAttribute{
Description: "The minimum required TLS version for API calls." +
"Supported values: `1.0|1.1|1.2|1.3`. Defaults to `1.3`.",
Optional: true,
},
"otp": schema.StringAttribute{
Description: "The one-time password for the Proxmox VE API.",
Optional: true,
@ -228,6 +234,7 @@ func (p *proxmoxProvider) Configure(
apiToken := utils.GetAnyStringEnv("PROXMOX_VE_API_TOKEN")
endpoint := utils.GetAnyStringEnv("PROXMOX_VE_ENDPOINT")
insecure := utils.GetAnyBoolEnv("PROXMOX_VE_INSECURE")
minTLS := utils.GetAnyStringEnv("PROXMOX_VE_MIN_TLS")
username := utils.GetAnyStringEnv("PROXMOX_VE_USERNAME")
password := utils.GetAnyStringEnv("PROXMOX_VE_PASSWORD")
@ -243,6 +250,10 @@ func (p *proxmoxProvider) Configure(
insecure = config.Insecure.ValueBool()
}
if !config.MinTLS.IsNull() {
minTLS = config.MinTLS.ValueString()
}
if !config.Username.IsNull() {
username = config.Username.ValueString()
}
@ -278,6 +289,7 @@ func (p *proxmoxProvider) Configure(
conn, err := api.NewConnection(
endpoint,
insecure,
minTLS,
)
if err != nil {
resp.Diagnostics.AddError(

View File

@ -92,7 +92,7 @@ func getNodesClient() *nodes.Client {
panic(err)
}
conn, err := api.NewConnection(endpoint, true)
conn, err := api.NewConnection(endpoint, true, "")
if err != nil {
panic(err)
}

View File

@ -16,11 +16,13 @@ import (
"io"
"net/http"
"net/url"
"sort"
"strings"
"github.com/google/go-querystring/query"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
"golang.org/x/exp/maps"
"github.com/bpg/terraform-provider-proxmox/utils"
)
@ -59,7 +61,7 @@ type Connection struct {
}
// NewConnection creates and initializes a Connection instance.
func NewConnection(endpoint string, insecure bool) (*Connection, error) {
func NewConnection(endpoint string, insecure bool, minTLS string) (*Connection, error) {
u, err := url.ParseRequestURI(endpoint)
if err != nil {
return nil, errors.New(
@ -73,10 +75,15 @@ func NewConnection(endpoint string, insecure bool) (*Connection, error) {
)
}
version, err := GetMinTLSVersion(minTLS)
if err != nil {
return nil, err
}
var transport http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS13,
MinVersion: version,
InsecureSkipVerify: insecure, //nolint:gosec
},
}
@ -317,3 +324,24 @@ func validateResponseCode(res *http.Response) error {
return nil
}
// GetMinTLSVersion returns the minimum TLS version constant for the given string. If the string is empty,
// the default TLS version is returned. For unsupported TLS versions, an error is returned.
func GetMinTLSVersion(version string) (uint16, error) {
validVersions := map[string]uint16{
"": tls.VersionTLS13,
"1.3": tls.VersionTLS13,
"1.2": tls.VersionTLS12,
"1.1": tls.VersionTLS11,
"1.0": tls.VersionTLS10,
}
if val, ok := validVersions[strings.TrimSpace(version)]; ok {
return val, nil
}
valid := maps.Keys(validVersions)
sort.Strings(valid)
return 0, fmt.Errorf("unsupported minimal TLS version %s, must be one of: %s", version, strings.Join(valid, ", "))
}

View File

@ -50,6 +50,7 @@ func providerConfigure(_ context.Context, d *schema.ResourceData) (interface{},
apiToken := utils.GetAnyStringEnv("PROXMOX_VE_API_TOKEN", "PM_VE_API_TOKEN")
endpoint := utils.GetAnyStringEnv("PROXMOX_VE_ENDPOINT", "PM_VE_ENDPOINT")
insecure := utils.GetAnyBoolEnv("PROXMOX_VE_INSECURE", "PM_VE_INSECURE")
minTLS := utils.GetAnyStringEnv("PROXMOX_VE_MIN_TLS", "PM_VE_MIN_TLS")
username := utils.GetAnyStringEnv("PROXMOX_VE_USERNAME", "PM_VE_USERNAME")
password := utils.GetAnyStringEnv("PROXMOX_VE_PASSWORD", "PM_VE_PASSWORD")
otp := utils.GetAnyStringEnv("PROXMOX_VE_OTP", "PM_VE_OTP")
@ -66,6 +67,10 @@ func providerConfigure(_ context.Context, d *schema.ResourceData) (interface{},
insecure = v.(bool)
}
if v, ok := d.GetOk(mkProviderMinTLS); ok {
minTLS = v.(string)
}
if v, ok := d.GetOk(mkProviderUsername); ok {
username = v.(string)
}
@ -81,7 +86,7 @@ func providerConfigure(_ context.Context, d *schema.ResourceData) (interface{},
creds, err = api.NewCredentials(username, password, otp, apiToken)
diags = append(diags, diag.FromErr(err)...)
conn, err = api.NewConnection(endpoint, insecure)
conn, err = api.NewConnection(endpoint, insecure, minTLS)
diags = append(diags, diag.FromErr(err)...)
if diags.HasError() {

View File

@ -37,6 +37,7 @@ func TestProviderSchema(t *testing.T) {
mkProviderPassword,
mkProviderEndpoint,
mkProviderInsecure,
mkProviderMinTLS,
mkProviderOTP,
})
@ -45,6 +46,7 @@ func TestProviderSchema(t *testing.T) {
mkProviderPassword: schema.TypeString,
mkProviderEndpoint: schema.TypeString,
mkProviderInsecure: schema.TypeBool,
mkProviderMinTLS: schema.TypeString,
mkProviderOTP: schema.TypeString,
})

View File

@ -18,6 +18,7 @@ const (
dvProviderOTP = ""
mkProviderEndpoint = "endpoint"
mkProviderInsecure = "insecure"
mkProviderMinTLS = "min_tls"
mkProviderOTP = "otp"
mkProviderPassword = "password"
mkProviderUsername = "username"
@ -48,6 +49,12 @@ func createSchema() map[string]*schema.Schema {
Optional: true,
Description: "Whether to skip the TLS verification step.",
},
mkProviderMinTLS: {
Type: schema.TypeString,
Optional: true,
Description: "The minimum required TLS version for API calls." +
"Supported values: `1.0|1.1|1.2|1.3`. Defaults to `1.3`.",
},
mkProviderOTP: {
Type: schema.TypeString,
Optional: true,

View File

@ -39,6 +39,7 @@ const (
dvResourceVirtualEnvironmentFileSourceFileChecksum = ""
dvResourceVirtualEnvironmentFileSourceFileFileName = ""
dvResourceVirtualEnvironmentFileSourceFileInsecure = false
dvResourceVirtualEnvironmentFileSourceFileMinTLS = ""
dvResourceVirtualEnvironmentFileOverwrite = true
dvResourceVirtualEnvironmentFileSourceRawResize = 0
dvResourceVirtualEnvironmentFileTimeoutUpload = 1800
@ -57,6 +58,7 @@ const (
mkResourceVirtualEnvironmentFileSourceFileChecksum = "checksum"
mkResourceVirtualEnvironmentFileSourceFileFileName = "file_name"
mkResourceVirtualEnvironmentFileSourceFileInsecure = "insecure"
mkResourceVirtualEnvironmentFileSourceFileMinTLS = "min_tls"
mkResourceVirtualEnvironmentFileSourceRaw = "source_raw"
mkResourceVirtualEnvironmentFileSourceRawData = "data"
mkResourceVirtualEnvironmentFileSourceRawFileName = "file_name"
@ -155,6 +157,14 @@ func File() *schema.Resource {
ForceNew: true,
Default: dvResourceVirtualEnvironmentFileSourceFileInsecure,
},
mkResourceVirtualEnvironmentFileSourceFileMinTLS: {
Type: schema.TypeString,
Description: "The minimum required TLS version for HTTPS sources." +
"Supported values: `1.0|1.1|1.2|1.3`. Defaults to `1.3`.",
Optional: true,
ForceNew: true,
Default: dvResourceVirtualEnvironmentFileSourceFileMinTLS,
},
},
},
MaxItems: 1,
@ -372,6 +382,7 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
sourceFileBlock := sourceFile[0].(map[string]interface{})
sourceFilePath := sourceFileBlock[mkResourceVirtualEnvironmentFileSourceFilePath].(string)
sourceFileChecksum := sourceFileBlock[mkResourceVirtualEnvironmentFileSourceFileChecksum].(string)
sourceFileMinTLS := sourceFileBlock[mkResourceVirtualEnvironmentFileSourceFileMinTLS].(string)
sourceFileInsecure := sourceFileBlock[mkResourceVirtualEnvironmentFileSourceFileInsecure].(bool)
if fileIsURL(d) {
@ -379,10 +390,15 @@ func fileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag
"url": sourceFilePath,
})
version, e := api.GetMinTLSVersion(sourceFileMinTLS)
if e != nil {
return diag.FromErr(e)
}
httpClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS13,
MinVersion: version,
InsecureSkipVerify: sourceFileInsecure,
},
},