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:
parent
7d94bf73ec
commit
01ff2cb7db
@ -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`.
|
||||
|
@ -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.
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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, ", "))
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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,
|
||||
})
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user