Skip to content

Commit abe21d8

Browse files
Merge branch 'develop'
2 parents faafd06 + 488db0d commit abe21d8

6 files changed

Lines changed: 818 additions & 11 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/dockcmd
22
/release
33
.idea
4-
*.yaml
4+
*.yaml
5+
*.json

README.md

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
`dockcmd` is a tool providing a collection of [BoxOps](https://boxops.io) utility functions. Which can be used standalone or to accelerate CI/CD with BoxBoat's [dockhand](https://github.com/boxboat/dockhand).
55

6+
7+
***
68
## `aws`
79

10+
811
AWS utilities are under the `aws` sub-command. For authentication, AWS commands make use of the standard AWS credentials providers and will check in order:
912

1013
* Access Key/Secret key
@@ -43,10 +46,78 @@ foo:
4346
keyC: '<value-of-secret/foo-charlie-c-from-aws-secrets-manager>'
4447
keyD: "<value-of-secret/root-d-from-aws-secrets-manager>"
4548
```
49+
***
50+
## `azure`
51+
52+
Azure utilities are under the `azure` sub-command. For authentication, Azure commands make use of these flags and environment variables:
53+
54+
* Client Id/Client Secret
55+
* Environment: `${AZURE_CLIENT_ID}` `${AZURE_CLIENT_SECRET}`
56+
* Args: `--client-id <access-key>` `--client-secret <secret-key>`
57+
* Tenant:
58+
* Environment: `${AZURE_TENANT_ID}`
59+
* Args: `--tenant <tenant-id>`
60+
61+
See `dockcmd azure --help` for more details on `azure` flags.
62+
63+
### `get-secrets`
64+
65+
Retrieve secrets stored as JSON from AWS Secrets Manager. Input files are defined using go templating and `dockcmd` supports sprig functions, as well as alternate template delimiters `<< >>` using `--use-alt-delims`. External values can be passed in using `--set key=value`
66+
67+
`dockcmd azure get-secrets --set TargetEnv=prod --input-file secret-values.yaml`
68+
69+
`secret-values.yaml`:
70+
```
71+
---
72+
foo:
73+
keyA: {{ (azureJson "foo" "a") | squote }}
74+
keyB: {{ (azureJson "foo" "b") | squote }}
75+
charlie:
76+
keyC: {{ (azureJson "foo-charlie" "c") | squote }}
77+
keyD: {{ (azureText "root" ) | quote }}
78+
```
79+
80+
output:
81+
```
82+
foo:
83+
keyA: '<value-of-secret/foo-a-frome-azure-key-vault>'
84+
keyB: '<value-of-secret/foo-b-frome-azure-key-vault>'
85+
charlie:
86+
keyC: '<value-of-secret/foo-charlie-c-frome-azure-key-vault>'
87+
keyD: "<value-of-secret/root-from-azure-key-vault>"
88+
```
89+
90+
***
91+
## `es`
92+
Elasticsearch utilities are under the `es` sub-command. Currently supports Elasticsearch API major version v6 and v7. For authentication, `es` commands will use the environment or credentials passed in as arguments:
93+
94+
#### Basic Auth
95+
`--username <username>` or `${ES_USERNAME}`
96+
`--password <password>` or `${ES_PASSWORD}`
97+
98+
#### API Key
99+
Note, if you set the `api-key` then it will override any Basic Auth parameters provided:
100+
`--api-key <base64-encoded-auth-token>` or `${ES_API_KEY}`
101+
102+
#### No Auth
103+
If authorization is not required, simply omit the above flags.
104+
105+
See `dockcmd es --help` for more details on `es` flags.
106+
107+
### `get-indices`
108+
Retrieve indices from ES, output is json payload.
109+
110+
See `dockcmd es get-indices --help` for more details.
111+
112+
### `delete-indices`
113+
Delete indices from ES.
114+
115+
See `dockcmd es delete-indices --help` for more details
46116

117+
***
47118
## `vault`
48119

49-
Vault utilities are under the `aws` sub-command. For authentication, `vault` commands will use the environment or credentials passed in as arguments:
120+
Vault utilities are under the `vault` sub-command. For authentication, `vault` commands will use the environment or credentials passed in as arguments:
50121

51122
`--vault-token <vault-token>` or `${VAULT_TOKEN}`
52123
or

cmd/azure.go

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
// Copyright © 2019 BoxBoat engineering@boxboat.com
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cmd
16+
17+
import (
18+
"context"
19+
"encoding/json"
20+
"fmt"
21+
"github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/keyvault/keyvault"
22+
kvauth "github.com/Azure/azure-sdk-for-go/services/keyvault/auth"
23+
"github.com/spf13/cobra"
24+
"github.com/spf13/viper"
25+
"os"
26+
"text/template"
27+
)
28+
29+
var (
30+
initialized = false
31+
azureTenantID string
32+
azureClientID string
33+
azureClientSecret string
34+
azureKeyVaultName string
35+
azureKeyVaultClient keyvault.BaseClient
36+
azureSecretCache map[string]map[string]interface{}
37+
)
38+
39+
func getKeyVaultClient() keyvault.BaseClient {
40+
if !initialized {
41+
authorizer, err := kvauth.NewAuthorizerFromEnvironment()
42+
HandleError(err)
43+
azureKeyVaultClient = keyvault.New()
44+
azureKeyVaultClient.Authorizer = authorizer
45+
initialized = true
46+
}
47+
return azureKeyVaultClient
48+
}
49+
50+
func getAzureJSONSecret(secretName string, secretKey string) string {
51+
Logger.Debugf("Retrieving [%s][%s]", secretName, secretKey)
52+
53+
if val, ok := azureSecretCache[secretName]; ok {
54+
Logger.Debugf("Using cached [%s][%s]", secretName, secretKey)
55+
secretStr, ok := val[secretKey].(string)
56+
if !ok {
57+
HandleError(
58+
fmt.Errorf(
59+
"Could not convert [%s][%s] to string",
60+
secretName,
61+
secretKey))
62+
}
63+
return secretStr
64+
}
65+
66+
secretResp, err := getKeyVaultClient().GetSecret(
67+
context.Background(),
68+
"https://"+azureKeyVaultName+".vault.azure.net",
69+
secretName, "")
70+
HandleError(err)
71+
secretJSON := *secretResp.Value
72+
var response map[string]interface{}
73+
json.Unmarshal([]byte(secretJSON), &response)
74+
75+
secretStr, ok := response[secretKey].(string)
76+
if !ok {
77+
HandleError(
78+
fmt.Errorf(
79+
"Could not convert Key Vault response[%s][%s] to string",
80+
secretName,
81+
secretKey))
82+
}
83+
if azureSecretCache[secretName] == nil {
84+
azureSecretCache[secretName] = make(map[string]interface{})
85+
}
86+
azureSecretCache[secretName] = response
87+
return secretStr
88+
}
89+
90+
func getAzureTextSecret(secretName string) string {
91+
Logger.Debugf("getAzureTextSecret [%s]", secretName)
92+
93+
secretResp, err := getKeyVaultClient().GetSecret(
94+
context.Background(),
95+
"https://"+azureKeyVaultName+".vault.azure.net",
96+
secretName, "")
97+
HandleError(err)
98+
secretStr := *secretResp.Value
99+
100+
return secretStr
101+
102+
}
103+
104+
// azureRegionCmdPersistentPreRunE checks required persistent tokens for azureCmd
105+
func azureCmdPersistentPreRunE(cmd *cobra.Command, args []string) error {
106+
if err := rootCmdPersistentPreRunE(cmd, args); err != nil {
107+
return err
108+
}
109+
Logger.Debugln("azureCmdPersistentPreRunE")
110+
111+
azureTenantID = viper.GetString("tenant")
112+
azureClientID = viper.GetString("client-id")
113+
azureClientSecret = viper.GetString("client-secret")
114+
115+
// ensure required environment variables are set
116+
os.Setenv("AZURE_TENANT_ID", azureTenantID)
117+
os.Setenv("AZURE_CLIENT_ID", azureClientID)
118+
os.Setenv("AZURE_CLIENT_SECRET", azureClientSecret)
119+
120+
return nil
121+
}
122+
123+
// azureCmd represents the azure command
124+
var azureCmd = &cobra.Command{
125+
Use: "azure",
126+
Short: "Azure Commands",
127+
Long: `Commands designed to facilitate interactions with Azure`,
128+
PersistentPreRunE: azureCmdPersistentPreRunE,
129+
Run: func(cmd *cobra.Command, args []string) {
130+
cmd.Help()
131+
},
132+
}
133+
134+
var azureGetSecretsCmd = &cobra.Command{
135+
Use: "get-secrets",
136+
Short: "Retrieve secrets from Azure Key Vault",
137+
Long: `Provide a go template file to request keys from Azure Key Vault
138+
139+
Supports sprig functions
140+
141+
Pass in values using --set <key=value> parameters
142+
143+
Example input and output:
144+
<secret-keys.yaml>
145+
---
146+
foo:
147+
keyA: {{ (azureJson "foo" "a") | squote }}
148+
keyB: {{ (azureJson "foo" "b") | squote }}
149+
charlie:
150+
keyC: {{ (azureJson "foo-charlie" "c") | squote }}
151+
keyD: {{ (azureText "root" ) | quote }}
152+
153+
154+
<secret-values.yaml>
155+
---
156+
foo:
157+
keyA: '<value-of-secret/foo-a-frome-azure-key-vault>'
158+
keyB: '<value-of-secret/foo-b-frome-azure-key-vault>'
159+
charlie:
160+
keyC: '<value-of-secret/foo-charlie-c-frome-azure-key-vault>'
161+
keyD: "<value-of-secret/root-from-azure-key-vault>"
162+
...
163+
`,
164+
Run: func(cmd *cobra.Command, args []string) {
165+
Logger.Debug("get-secrets called")
166+
167+
// create custom function map
168+
funcMap := template.FuncMap{
169+
"azureJson": getAzureJSONSecret,
170+
"azureText": getAzureTextSecret,
171+
}
172+
173+
var files []string
174+
if len(args) > 0 {
175+
files = args
176+
}
177+
178+
CommonGetSecrets(files, funcMap)
179+
180+
},
181+
PreRunE: func(cmd *cobra.Command, args []string) error {
182+
Logger.Debug("PreRunE")
183+
return ReadValuesMap()
184+
},
185+
}
186+
187+
func init() {
188+
rootCmd.AddCommand(azureCmd)
189+
190+
// azure command and common persistent flags
191+
azureCmd.AddCommand(azureGetSecretsCmd)
192+
azureCmd.PersistentFlags().StringVarP(
193+
&azureTenantID,
194+
"tenant",
195+
"",
196+
"",
197+
"Azure tenant ID can alternatively be set using ${AZURE_TENANT_ID}")
198+
viper.BindEnv("tenant", "AZURE_TENANT_ID")
199+
200+
azureCmd.PersistentFlags().StringVarP(
201+
&azureClientID,
202+
"client-id",
203+
"",
204+
"",
205+
"Azure Client ID can alternatively be set using ${AZURE_CLIENT_ID}")
206+
207+
azureCmd.PersistentFlags().StringVarP(
208+
&azureClientSecret,
209+
"client-secret",
210+
"",
211+
"",
212+
"Azure Client Secret Key can alternatively be set using ${AZURE_CLIENT_SECRET}")
213+
214+
viper.BindEnv("tenant", "AZURE_TENANT_ID")
215+
viper.BindEnv("client-id", "AZURE_CLIENT_ID")
216+
viper.BindEnv("client-secret", "AZURE_CLIENT_SECRET")
217+
viper.BindPFlags(azureCmd.PersistentFlags())
218+
219+
azureGetSecretsCmd.PersistentFlags().StringVarP(
220+
&azureKeyVaultName,
221+
"key-vault",
222+
"",
223+
"",
224+
"Azure Key Vault Name")
225+
AddValuesArraySupport(azureGetSecretsCmd, &commonValues)
226+
AddUseAlternateDelimitersSupport(azureGetSecretsCmd, &commonUseAlternateDelims)
227+
AddEditInPlaceSupport(azureGetSecretsCmd, &commonEditInPlace)
228+
229+
AddInputFileSupport(azureGetSecretsCmd, &commonGetSecretsInputFile)
230+
AddOutputFileSupport(azureGetSecretsCmd, &commonGetSecretsOutputFile)
231+
232+
azureSecretCache = make(map[string]map[string]interface{})
233+
}

0 commit comments

Comments
 (0)