diff --git a/.gitignore b/.gitignore index d96ff5264..af98bedbd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /cmd/hcloud/hcloud hcloud_cli.p12 coverage.txt +/.idea \ No newline at end of file diff --git a/internal/state/config/options.go b/internal/state/config/options.go index 7f9c21d69..cbf3e2983 100644 --- a/internal/state/config/options.go +++ b/internal/state/config/options.go @@ -115,6 +115,24 @@ var ( &overrides{configKey: "active_context"}, ) + OptionStaticIp = newOpt( + "static-ip", + "Set a static ip for Hetzner API endpoint", + "", + DefaultPreferenceFlags, + nil, + nil, + ) + + OptionRootCA = newOpt( + "root-ca", + "Set a custom root CA for Hetzner API endpoint", + "", + DefaultPreferenceFlags, + nil, + nil, + ) + OptionEndpoint = newOpt( "endpoint", "Hetzner Cloud API endpoint", diff --git a/internal/state/state.go b/internal/state/state.go index c46f0b1b0..6c64ab833 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -2,8 +2,12 @@ package state import ( "context" + "crypto/tls" + "crypto/x509" "fmt" "io" + "net" + "net/http" "os" "strings" @@ -88,13 +92,14 @@ func (c *state) newClient() (hcapi2.Client, error) { return nil, err } + var debugWriter io.Writer + if debug { filePath, err := config.OptionDebugFile.Get(c.config) if err != nil { return nil, err } - var debugWriter io.Writer if filePath == "" { debugWriter = os.Stderr } else { @@ -128,5 +133,43 @@ func (c *state) newClient() (hcapi2.Client, error) { })) } + staticIp, err := config.OptionStaticIp.Get(c.config) + if err != nil { + return nil, err + } + + rootCA, err := config.OptionRootCA.Get(c.config) + if err != nil { + return nil, err + } + + if staticIp != "" || rootCA != "" { + tr := &http.Transport{} + + if staticIp != "" { + tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + split := strings.Split(addr, ":") + return net.Dial(network, fmt.Sprintf("%s:%s", staticIp, split[1])) + } + } + + if rootCA != "" { + certs := x509.NewCertPool() + pemData, err := os.ReadFile(rootCA) + if err != nil && debug { + fmt.Fprintf(debugWriter, "Error reading root CA certificate %s:\n%s\n", rootCA, err) + } + if err == nil { + certs.AppendCertsFromPEM(pemData) + tr.TLSClientConfig = &tls.Config{ + RootCAs: certs, + } + } + } + + client := &http.Client{Transport: tr} + opts = append(opts, hcloud.WithHTTPClient(client)) + } + return hcapi2.NewClient(opts...), nil }