Skip to content

Commit 9a0ccf0

Browse files
feat: Add API key authentication support
implementation: * Updated provider schema to include `aqua_api_key` and `aqua_api_secret`. * Modified provider configuration to handle API key authentication. * Updated examples to demonstrate API key usage. * Updated documentation to reflect new authentication method. * Added tests for API key authentication.
1 parent 705ad8a commit 9a0ccf0

File tree

13 files changed

+346
-76
lines changed

13 files changed

+346
-76
lines changed

DEVELOPMENT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ git clone https://github.com/aquasecurity/terraform-provider-aquasec.git
3232
3333
cd terraform-provider-aquasec
3434
35-
git checkout v0.10.0
35+
git checkout v0.11.0
3636
```
3737

3838
**Build and install the provider**

GNUmakefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
# This ensures docker volumes are mounted from within provider directory instead.
33
PROVIDER_DIR := $(abspath $(lastword $(dir $(MAKEFILE_LIST))))
44
TEST := "$(PROVIDER_DIR)/aquasec"
5-
HOSTNAME := github.com
5+
HOSTNAME := registry.terraform.io
66
NAMESPACE := aquasec
77
NAME := aquasec
88
BINARY := terraform-provider-${NAME}
9-
VERSION := 0.10.0
9+
VERSION := 0.11.0
1010
OS_ARCH := $(shell go env GOOS)_$(shell go env GOARCH)
1111

1212
default: build

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ To quickly get started using the Aquasec provider for Terraform, configure the p
4343
terraform {
4444
required_providers {
4545
aquasec = {
46-
version = "0.10.0"
46+
version = "0.11.0"
4747
source = "aquasecurity/aquasec"
4848
}
4949
}
@@ -54,6 +54,15 @@ provider "aquasec" {
5454
aqua_url = "https://aquaurl.com"
5555
password = "@password"
5656
}
57+
58+
//Alternative API Based authentication
59+
provider "aquasec" {
60+
aqua_api_key = var.aquasec_api_key
61+
aqua_api_secret = var.aquasec_api_secret
62+
validity = 240
63+
allowed_endpoints = ["ANY"]
64+
csp_roles = ["Admin"]
65+
}
5766
```
5867
## Using the Aquasec provider SaaS solution
5968

aquasec/init_test.go

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,49 @@ import (
1212
func init() {
1313
log.Println("setup suite")
1414
var (
15-
present, verifyTLS bool
16-
username, password, aquaURL, verifyTLSString, caCertPath string
17-
err error
18-
caCertByte []byte
15+
present bool
16+
username, password, aquaURL string
17+
verifyTLS, useAPIKey bool
18+
verifyTLSString, apiKey, secretKey, useAPIKeyStr string
19+
caCertPath string
20+
err error
21+
caCertByte []byte
1922
)
2023

21-
username, present = os.LookupEnv("AQUA_USER")
24+
aquaURL, present = os.LookupEnv("AQUA_URL")
2225
if !present {
23-
panic("AQUA_USER env is missing, please set it")
26+
panic("AQUA_URL env is missing, please set it")
2427
}
2528

26-
password, present = os.LookupEnv("AQUA_PASSWORD")
27-
if !present {
28-
panic("AQUA_PASSWORD env is missing, please set it")
29+
apiKey = os.Getenv("AQUA_API_KEY")
30+
secretKey = os.Getenv("AQUA_API_SECRET")
31+
useAPIKeyStr = os.Getenv("AQUA_USE_API_KEY")
32+
useAPIKey = false
33+
if useAPIKeyStr != "" {
34+
var err error
35+
useAPIKey, err = strconv.ParseBool(useAPIKeyStr)
36+
if err != nil {
37+
panic(fmt.Sprintf("Invalid boolen for AQUA_USE_API_KEY: %v", err))
38+
}
2939
}
3040

31-
aquaURL, present = os.LookupEnv("AQUA_URL")
32-
if !present {
33-
panic("AQUA_URL env is missing, please set it")
41+
if !useAPIKey {
42+
username, present = os.LookupEnv("AQUA_USER")
43+
if !present {
44+
panic("AQUA_USER env is missing, please set it")
45+
}
46+
47+
password, present = os.LookupEnv("AQUA_PASSWORD")
48+
if !present {
49+
panic("AQUA_PASSWORD env is missing, please set it")
50+
}
3451
}
3552

3653
verifyTLSString, present = os.LookupEnv("AQUA_TLS_VERIFY")
3754
if !present {
3855
verifyTLSString = "true"
3956
}
57+
verifyTLS, _ = strconv.ParseBool(verifyTLSString)
4058

4159
caCertPath, present = os.LookupEnv("AQUA_CA_CERT_PATH")
4260
if present {
@@ -46,12 +64,14 @@ func init() {
4664
panic("Unable to read CA certificates")
4765
}
4866
}
49-
panic("AQUA_CA_CERT_PATH env is missing, please set it")
5067
}
5168

52-
verifyTLS, _ = strconv.ParseBool(verifyTLSString)
53-
54-
aquaClient := client.NewClient(aquaURL, username, password, verifyTLS, caCertByte)
69+
var aquaClient *client.Client
70+
if useAPIKey {
71+
aquaClient = client.NewClientWithAPIKey(aquaURL, apiKey, secretKey, verifyTLS, caCertByte)
72+
} else {
73+
aquaClient = client.NewClientWithTokenAuth(aquaURL, username, password, verifyTLS, caCertByte)
74+
}
5575
token, url, err := aquaClient.GetAuthToken()
5676

5777
if err != nil {

aquasec/provider.go

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@ import (
1616

1717
// Config - godoc
1818
type Config struct {
19-
Username string `json:"tenant"`
20-
Password string `json:"token"`
21-
AquaURL string `json:"aqua_url"`
19+
Username string `json:"tenant"`
20+
Password string `json:"token"`
21+
AquaURL string `json:"aqua_url"`
22+
APIKey string `json:"aqua_api_key"`
23+
SecretKey string `json:"aqua_api_secret"`
24+
Validity int `json:"validity"`
25+
AllowedEndpoints []string `json:"allowed_endpoints"`
26+
CSPRoles []string `json:"csp_roles"`
2227
}
2328

2429
// Provider -
@@ -45,6 +50,20 @@ func Provider(v string) *schema.Provider {
4550
DefaultFunc: schema.EnvDefaultFunc("AQUA_URL", nil),
4651
Description: "This is the base URL of your Aqua instance. Can alternatively be sourced from the `AQUA_URL` environment variable.",
4752
},
53+
"aqua_api_key": {
54+
Type: schema.TypeString,
55+
Optional: true,
56+
Sensitive: true,
57+
DefaultFunc: schema.EnvDefaultFunc("AQUA_API_KEY", nil),
58+
Description: "API key for authentication. If set, API key mode is used instead of token-based auth.",
59+
},
60+
"aqua_api_secret": {
61+
Type: schema.TypeString,
62+
Optional: true,
63+
Sensitive: true,
64+
DefaultFunc: schema.EnvDefaultFunc("AQUA_API_SECRET", nil),
65+
Description: "Shared secret for API key HMAC signing.",
66+
},
4867
"verify_tls": {
4968
Type: schema.TypeBool,
5069
Optional: true,
@@ -69,6 +88,27 @@ func Provider(v string) *schema.Provider {
6988
Default: true,
7089
Description: "Skip provider credential validation when set to false.",
7190
},
91+
"validity": {
92+
Type: schema.TypeInt,
93+
Optional: true,
94+
Default: 240,
95+
Description: "Lifetime of the token, in minutes. Set between 1 and 1500. Once the token expires, need to generate a new one",
96+
},
97+
"allowed_endpoints": {
98+
Type: schema.TypeList,
99+
Optional: true,
100+
Description: "API methods the token has access to",
101+
Elem: &schema.Schema{
102+
Type: schema.TypeString,
103+
},
104+
},
105+
"csp_roles": {
106+
Type: schema.TypeList,
107+
Optional: true,
108+
Elem: &schema.Schema{
109+
Type: schema.TypeString,
110+
},
111+
},
72112
},
73113
ResourcesMap: map[string]*schema.Resource{
74114
"aquasec_user": resourceUser(),
@@ -143,23 +183,23 @@ func Provider(v string) *schema.Provider {
143183
}
144184
}
145185

146-
func getProviderConfigurationFromFile(d *schema.ResourceData) (string, string, string, error) {
186+
func getProviderConfigurationFromFile(d *schema.ResourceData) (string, string, string, string, string, error) {
147187
log.Print("[DEBUG] Trying to load configuration from file")
148188
if configPath, ok := d.GetOk("config_path"); ok && configPath.(string) != "" {
149189
path, err := homedir.Expand(configPath.(string))
150190
if err != nil {
151191
log.Printf("[DEBUG] Failed to expand config file path %s, error %s", configPath, err)
152-
return "", "", "", nil
192+
return "", "", "", "", "", nil
153193
}
154194
if _, err := os.Stat(path); os.IsNotExist(err) {
155195
log.Printf("[DEBUG] Terraform config file %s does not exist, error %s", path, err)
156-
return "", "", "", nil
196+
return "", "", "", "", "", nil
157197
}
158198
log.Printf("[DEBUG] Terraform configuration file is: %s", path)
159199
configFile, err := os.Open(path)
160200
if err != nil {
161201
log.Printf("[DEBUG] Unable to open Terraform configuration file %s", path)
162-
return "", "", "", fmt.Errorf("Unable to open terraform configuration file. Error %v", err)
202+
return "", "", "", "", "", fmt.Errorf("Unable to open terraform configuration file. Error %v", err)
163203
}
164204
defer configFile.Close()
165205

@@ -168,11 +208,11 @@ func getProviderConfigurationFromFile(d *schema.ResourceData) (string, string, s
168208
err = json.Unmarshal(configBytes, &config)
169209
if err != nil {
170210
log.Printf("[DEBUG] Failed to parse config file %s", path)
171-
return "", "", "", fmt.Errorf("Invalid terraform configuration file format. Error %v", err)
211+
return "", "", "", "", "", fmt.Errorf("Invalid terraform configuration file format. Error %v", err)
172212
}
173-
return config.Username, config.Password, config.AquaURL, nil
213+
return config.Username, config.Password, config.AquaURL, config.APIKey, config.SecretKey, nil
174214
}
175-
return "", "", "", nil
215+
return "", "", "", "", "", nil
176216
}
177217

178218
func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
@@ -183,32 +223,35 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}
183223
username := d.Get("username").(string)
184224
password := d.Get("password").(string)
185225
aquaURL := d.Get("aqua_url").(string)
226+
apiKey := d.Get("aqua_api_key").(string)
227+
secretkey := d.Get("aqua_api_secret").(string)
186228
verifyTLS := d.Get("verify_tls").(bool)
187229
caCertPath := d.Get("ca_certificate_path").(string)
188230
validate := d.Get("validate").(bool)
189231

190-
if username == "" && password == "" && aquaURL == "" {
191-
username, password, aquaURL, err = getProviderConfigurationFromFile(d)
232+
if username == "" && password == "" && aquaURL == "" && apiKey == "" && secretkey == "" {
233+
username, password, aquaURL, apiKey, secretkey, err = getProviderConfigurationFromFile(d)
192234
if err != nil && validate {
193235
return nil, diag.FromErr(err)
194236
}
195237
}
196238

197239
if validate {
198-
if username == "" {
199-
diags = append(diags, diag.Diagnostic{
200-
Severity: diag.Error,
201-
Summary: "Initializing provider, username parameter is missing.",
202-
})
203-
}
240+
if apiKey == "" {
241+
if username == "" {
242+
diags = append(diags, diag.Diagnostic{
243+
Severity: diag.Error,
244+
Summary: "Initializing provider, username parameter is missing.",
245+
})
246+
}
204247

205-
if password == "" {
206-
diags = append(diags, diag.Diagnostic{
207-
Severity: diag.Error,
208-
Summary: "Initializing provider, password parameter is missing.",
209-
})
248+
if password == "" {
249+
diags = append(diags, diag.Diagnostic{
250+
Severity: diag.Error,
251+
Summary: "Initializing provider, password parameter is missing.",
252+
})
253+
}
210254
}
211-
212255
if aquaURL == "" {
213256
diags = append(diags, diag.Diagnostic{
214257
Severity: diag.Error,
@@ -235,7 +278,21 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}
235278
return nil, diags
236279
}
237280

238-
aquaClient := client.NewClient(aquaURL, username, password, verifyTLS, caCertByte)
281+
var aquaClient *client.Client
282+
if apiKey != "" {
283+
aquaClient = client.NewClientWithAPIKey(aquaURL, apiKey, secretkey, verifyTLS, caCertByte)
284+
if v, ok := d.GetOk("validity"); ok {
285+
aquaClient.Validity = v.(int)
286+
}
287+
if v, ok := d.GetOk("allowed_endpoints"); ok {
288+
aquaClient.AllowedEndpoints = convertStringArr(v.([]interface{}))
289+
}
290+
if v, ok := d.GetOk("csp_roles"); ok {
291+
aquaClient.CSPRoles = convertStringArr(v.([]interface{}))
292+
}
293+
} else {
294+
aquaClient = client.NewClientWithTokenAuth(aquaURL, username, password, verifyTLS, caCertByte)
295+
}
239296

240297
if validate {
241298
token, tokenPresent := os.LookupEnv("TESTING_AUTH_TOKEN")

aquasec/provider_test.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package aquasec
22

33
import (
44
"os"
5+
"strconv"
56
"testing"
67

78
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -36,16 +37,27 @@ func testAccPreCheck(t *testing.T) {
3637
if _, err := os.Stat(configPath); !os.IsNotExist(err) {
3738
return
3839
}
39-
if err := os.Getenv("AQUA_USER"); err == "" {
40-
t.Fatal("AQUA_USER must be set for acceptance tests")
41-
}
42-
43-
if err := os.Getenv("AQUA_PASSWORD"); err == "" {
44-
t.Fatal("AQUA_PASSWORD must be set for acceptance tests")
45-
}
40+
useAPIKeyStr := os.Getenv("AQUA_USE_API_KEY")
41+
useAPiKey, _ := strconv.ParseBool(useAPIKeyStr)
4642

4743
if err := os.Getenv("AQUA_URL"); err == "" {
4844
t.Fatal("AQUA_URL must be set for acceptance tests")
4945
}
5046

47+
if !useAPiKey {
48+
if err := os.Getenv("AQUA_USER"); err == "" {
49+
t.Fatal("AQUA_USER must be set for acceptance tests")
50+
}
51+
52+
if err := os.Getenv("AQUA_PASSWORD"); err == "" {
53+
t.Fatal("AQUA_PASSWORD must be set for acceptance tests")
54+
}
55+
} else {
56+
if os.Getenv("AQUA_API_KEY") == "" {
57+
t.Fatal("AQUA_API_KEY must be set for API key authentication")
58+
}
59+
if os.Getenv("AQUA_API_SECRET") == "" {
60+
t.Fatal("AQUA_API_SECRET must be set for API key authentication")
61+
}
62+
}
5163
}

0 commit comments

Comments
 (0)