Skip to content

Commit

Permalink
feat: Add an option to initialize the client with the private key
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleg Neychev committed Sep 15, 2021
1 parent ec73f27 commit d638c23
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 14 deletions.
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Terraform provider for [Netbox.](https://netbox.readthedocs.io/en/stable/)

## Compatibility with Netbox

Version 0.x.y => Netbox 2.8
Version 1.x.y => Netbox 2.9
Version 0.x.y => Netbox 2.8
Version 1.x.y => Netbox 2.9

## Building the provider

Expand Down Expand Up @@ -78,19 +78,25 @@ $ make localinstall

## Using the provider

The definition of the provider is optional.
All the parameters could be setup by environment variables.
The definition of the provider is optional.
All the parameters could be setup by environment variables.

```hcl
provider netbox {
# Environment variable NETBOX_URL
url = "127.0.0.1:8000"
# Environment variable NETBOX_TOKEN
token = "c07a2db4adb8b1e7f75e7c4369964e92f7680512"
# Environment variable NETBOX_SCHEME
scheme = "http"
# Environment variable NETBOX_INSECURE
insecure = "true"
# Environment variable NETBOX_PRIVATE_KEY_FILE
private_key_file = "/path/to/private/key"
}
```

Expand All @@ -103,8 +109,8 @@ commits](https://www.conventionalcommits.org/en/v1.0.0-beta.2/) rules.

## Examples

You can find some examples in the examples folder.
Each example can be executed directly with command terraform init & terraform apply.
You can find some examples in the examples folder.
Each example can be executed directly with command terraform init & terraform apply.
You can set different environment variables for your test:
* NETBOX_URL to define the URL and the port (127.0.0.1:8000 by default)
* NETBOX_TOKEN to define the TOKEN to access the application (empty by default)
Expand Down
11 changes: 9 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Terraform provider for [Netbox.](https://netbox.readthedocs.io/en/stable/)

## Compatibility with Netbox

Version 0.x.y => Netbox 2.8
Version 1.x.y => Netbox 2.9
Version 0.x.y => Netbox 2.8
Version 1.x.y => Netbox 2.9

## Example Usage

Expand All @@ -22,6 +22,12 @@ provider netbox {
# Environment variable NETBOX_SCHEME
scheme = "http"
# Environment variable NETBOX_INSECURE
insecure = "true"
# Environment variable NETBOX_PRIVATE_KEY_FILE
private_key_file = "/path/to/private/key"
}
```

Expand All @@ -32,3 +38,4 @@ provider netbox {
* `token` or `NETBOX_TOKEN` environment variable to define the TOKEN to access the application (empty by default)
* `scheme` or `NETBOX_SCHEME` environment variable to define the SCHEME of the URL (https by default)
* `insecure` or `NETBOX_INSECURE` environment variable to skip or not the TLS certificat validation (false by default)
* `private_key_file` or `NETBOX_PRIVATE_KEY_FILE` environment variable to add a private key to work with encoded data like secrets (empty by default)
60 changes: 56 additions & 4 deletions netbox/provider.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package netbox

import (
"crypto/tls"
"fmt"
"net/http"

runtimeclient "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
Expand Down Expand Up @@ -46,6 +48,12 @@ func Provider() *schema.Provider {
DefaultFunc: schema.EnvDefaultFunc("NETBOX_INSECURE", false),
Description: "Skip TLS certificate validation.",
},
"private_key_file": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("NETBOX_PRIVATE_KEY_FILE", ""),
Description: "Private Key used for Secrets",
},
},
DataSourcesMap: map[string]*schema.Resource{
"netbox_dcim_platform": dataNetboxDcimPlatform(),
Expand Down Expand Up @@ -149,17 +157,61 @@ func configureProvider(d *schema.ResourceData) (interface{}, error) {
token := d.Get("token").(string)
scheme := d.Get("scheme").(string)
insecure := d.Get("insecure").(bool)

defaultScheme := []string{scheme}
privateKeyFile := d.Get("private_key_file").(string)

var options runtimeclient.TLSClientOptions
options.InsecureSkipVerify = insecure
tlsConfig, _ := runtimeclient.TLSClientAuth(options)

clientWithTLSOptions, _ := runtimeclient.TLSClient(options)
headers := make(map[string]string)

if privateKeyFile != "" {
privateKey := ReadRSAKey(privateKeyFile)
if privateKey == "" {
return nil, fmt.Errorf("Error reading the private key file.")
}
sessionKey := GetSessionKey(fmt.Sprintf("%s://%s", scheme, url), token, privateKey)
if sessionKey == "" {
return nil, fmt.Errorf("The provided private key is invalid.")
}
headers["X-Session-Key"] = sessionKey
}
// Create a custom client
// Override the default transport with a RoundTripper to inject dynamic headers
// Add TLSOptions
cli := &http.Client{
Transport: &transport{
headers: headers,
TLSClientConfig: tlsConfig,
},
}

t := runtimeclient.NewWithClient(url, basepath, defaultScheme, clientWithTLSOptions)
defaultScheme := []string{scheme}

t := runtimeclient.NewWithClient(url, basepath, defaultScheme, cli)
t.DefaultAuthentication = runtimeclient.APIKeyAuth(authHeaderName, "header",
fmt.Sprintf(authHeaderFormat, token))

return client.New(t, strfmt.Default), nil
}

type transport struct {
headers map[string]string
base http.RoundTripper
TLSClientConfig *tls.Config
}

func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
// Add headers to request
for k, v := range t.headers {
req.Header.Add(k, v)
}
base := t.base
if base == nil {
// init an http.Transport with TLSOptions
customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = t.TLSClientConfig
base = customTransport
}
return base.RoundTrip(req)
}
42 changes: 42 additions & 0 deletions netbox/util.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package netbox

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"

netboxclient "github.com/netbox-community/go-netbox/netbox/client"
"github.com/netbox-community/go-netbox/netbox/client/virtualization"
"github.com/netbox-community/go-netbox/netbox/models"
Expand Down Expand Up @@ -210,3 +216,39 @@ func convertCustomFieldsFromTerraformToAPIUpdate(stateCustomFields, resourceCust

return toReturn
}

func ReadRSAKey(filePath string) (res string) {
data, err := ioutil.ReadFile(filePath)
if err != nil {
return ""
}
return string(data)
}

func GetSessionKey(destinationUrl string, token string, rsaKey string) string {
privateKey := rsaKey
data := url.Values{}
data.Set("private_key", privateKey) // set private key string
destinationUrl = destinationUrl + "/api/secrets/get-session-key/"

req, err := http.NewRequest("POST", destinationUrl, strings.NewReader(data.Encode())) // URL-enconded payload
if err != nil {
//
return ""
}

req.Header.Set("Authorization", "Token "+token)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json; indent=4")

resp, err := http.DefaultClient.Do(req)
if err != nil {
return ""
}

content, err := ioutil.ReadAll(resp.Body)
m := make(map[string]string)
err = json.Unmarshal(content, &m) // convert json to map

return m["session_key"]
}

0 comments on commit d638c23

Please sign in to comment.