-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpath_config_root.go
178 lines (154 loc) · 5.6 KB
/
path_config_root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package exoscale
import (
"context"
"errors"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
const (
configRootStoragePath = "config/root"
configAPIEnvironment = "api_environment"
configRootAPIKey = "root_api_key"
configRootAPISecret = "root_api_secret"
configZone = "zone"
configAPIKeyNamePrefix = "api_key_name_prefix"
)
var (
pathConfigRootHelpSyn = "Configure the root Exoscale API credentials"
pathConfigRootHelpDesc = `
Configure the root Exoscale API credentials that will be used to manage the IAM Keys
that are handled by Vault.
This plugin currently supports both our new IAM API Keys (referred to as "v3 API key" in our API)
and our legacy IAM keys (referred to as "IAM Access Key" in our API)
IAM API Keys (recommended)
==========================
The root API Key must have the permissions to perform the following IAM operations:
create-api-key, delete-api-key, get-api-key, list-api-keys, list-iam-roles, get-iam-role"
This can be achieved with the following role policy :
{
"default-service-strategy": "deny",
"services": {
"iam": {
"type": "rules",
"rules": [
{
"expression": "operation in ['create-api-key', 'delete-api-key', 'get-api-key', 'list-api-keys', 'list-iam-roles', 'get-iam-role']",
"action": "allow"
}
]
}
}
}
It is possible to restrict the creation of keys to a predefined list of roles by using the
parameters.role_id variable in the CEL expression, please refer to the IAM documentation for more information.
Legacy IAM Access Keys (deprecated)
===================================
With legacy IAM the Access Keys that are created must have a subset of the permissions of the
root access key. If you want to create any access key, the root key must be unrestricted.
`
errMissingAPICredentials = errors.New("missing root API root_api_key or root_api_secret")
)
type ExoscaleConfig struct {
APIEnvironment string `json:"api_environment"`
RootAPIKey string `json:"root_api_key"`
RootAPISecret string `json:"root_api_secret"`
Zone string `json:"zone"`
APIKeyNamePrefix string `json:"api_key_name_prefix"`
}
func (b *exoscaleBackend) pathConfigRoot() *framework.Path {
return &framework.Path{
Pattern: "config/root",
Fields: map[string]*framework.FieldSchema{
configAPIEnvironment: {
Type: framework.TypeString,
Description: "used only by the plugin developers, do not set",
Default: "api",
},
configRootAPIKey: {
Type: framework.TypeString,
Description: "Exoscale API key (required)",
DisplayAttrs: &framework.DisplayAttributes{Sensitive: true},
},
configRootAPISecret: {
Type: framework.TypeString,
Description: "Exoscale API secret (required)",
DisplayAttrs: &framework.DisplayAttributes{Sensitive: true},
},
configAPIKeyNamePrefix: {
Type: framework.TypeString,
Description: `Adds a prefix to the token name, just after 'vault'
e.g. with api_key_name_prefix=example the token name will be "vault-example-myrole-authname-0000000000000000000"
instead of "vault-myrole-authname-0000000000000000000" without (optional)`,
Default: "",
},
configZone: {
Type: framework.TypeString,
Description: `Exoscale API zone (optional, default: ch-gva-2)
note: API Keys are global, this only changes the zone used to perform API calls`,
Default: "ch-gva-2",
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.CreateOperation: &framework.PathOperation{Callback: b.pathConfigRootWrite},
logical.UpdateOperation: &framework.PathOperation{Callback: b.pathConfigRootWrite},
logical.ReadOperation: &framework.PathOperation{Callback: b.pathConfigRootRead},
},
HelpSynopsis: pathConfigRootHelpSyn,
HelpDescription: pathConfigRootHelpDesc,
}
}
func (b *exoscaleBackend) pathConfigRootRead(
ctx context.Context,
req *logical.Request,
_ *framework.FieldData,
) (*logical.Response, error) {
if !b.exo.configured {
return nil, ErrorBackendNotConfigured
}
return &logical.Response{
Data: map[string]interface{}{
configAPIEnvironment: b.exo.reqEndpoint.Env(),
configRootAPIKey: b.exo.apiKey,
configRootAPISecret: b.exo.apiSecret,
configZone: b.exo.reqEndpoint.Zone(),
configAPIKeyNamePrefix: b.exo.apiKeyNamePrefix,
},
}, nil
}
func (b *exoscaleBackend) pathConfigRootWrite(
ctx context.Context,
req *logical.Request,
data *framework.FieldData,
) (*logical.Response, error) {
config := ExoscaleConfig{
APIEnvironment: data.Get(configAPIEnvironment).(string),
Zone: data.Get(configZone).(string),
APIKeyNamePrefix: data.Get(configAPIKeyNamePrefix).(string),
RootAPIKey: data.Get(configRootAPIKey).(string),
RootAPISecret: data.Get(configRootAPISecret).(string),
}
if config.RootAPIKey == "" || config.RootAPISecret == "" {
return nil, errMissingAPICredentials
}
entry, err := logical.StorageEntryJSON(configRootStoragePath, config)
if err != nil {
return nil, err
}
if err := b.exo.LoadConfig(config); err != nil {
return nil, err
}
if err := req.Storage.Put(ctx, entry); err != nil {
return nil, err
}
res := &logical.Response{
Data: map[string]interface{}{
configAPIEnvironment: b.exo.reqEndpoint.Env(),
configRootAPIKey: b.exo.apiKey,
configRootAPISecret: b.exo.apiSecret,
configZone: b.exo.reqEndpoint.Zone(),
configAPIKeyNamePrefix: b.exo.apiKeyNamePrefix,
},
}
res.AddWarning("Access to the /config/root endpoint should be controlled via ACLs as it will return sensitive informations")
return res, nil
}