Update gcp secrets plugin (#9004)

This commit is contained in:
Jim Kalafut 2020-06-01 11:02:33 -07:00 committed by GitHub
parent eb0b3ac286
commit 34fab8ae09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1269 additions and 565 deletions

2
go.mod
View File

@ -86,7 +86,7 @@ require (
github.com/hashicorp/vault-plugin-secrets-ad v0.6.4-beta1.0.20200518124111-3dceeb3ce90e
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5
github.com/hashicorp/vault-plugin-secrets-azure v0.5.6
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.2
github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5
github.com/hashicorp/vault-plugin-secrets-kv v0.5.5
github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2

2
go.sum
View File

@ -508,6 +508,8 @@ github.com/hashicorp/vault-plugin-secrets-azure v0.5.6 h1:4PgQ5rCT29wW5PMyebEhPk
github.com/hashicorp/vault-plugin-secrets-azure v0.5.6/go.mod h1:Q0cIL4kZWnMmQWkBfWtyOd7+JXTEpAyU4L932PMHq3E=
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1 h1:APkzBSHo+sKeWxXCM1aGGwcbfKfVQFN3CHmNGHyfqL0=
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1/go.mod h1:jVTE1fuhRcBOb/gnCT9W++AnlwiyQEX4S8iVCKhKQsE=
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.2 h1:ovziWUzmj83UlVXK8tM926ZitLKa5ZwRvlMqVibWHEs=
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.2/go.mod h1:psRQ/dm5XatoUKLDUeWrpP9icMJNtu/jmscUr37YGK4=
github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5 h1:NigzA2v+h+cjBPl41pRirRwWELF+RPJGch/ys0Sijrc=
github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5/go.mod h1:b6RwFD1bny1zbfqhD35iGJdQYHRtJLx3HfBD109GO38=
github.com/hashicorp/vault-plugin-secrets-kv v0.5.5 h1:yLtfsAiJOkpRkk+OxQmFluQJ35OUw420Y+CwfGMWuSc=

View File

@ -33,7 +33,7 @@ type backend struct {
// cache directly.
cache *cache.Cache
iamResources iamutil.IamResourceParser
resources iamutil.ResourceParser
rolesetLock sync.Mutex
}
@ -50,7 +50,7 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend,
func Backend() *backend {
var b = &backend{
cache: cache.New(),
iamResources: iamutil.GetEnabledIamResources(),
resources: iamutil.GetEnabledResources(),
}
b.Backend = &framework.Backend{

View File

@ -0,0 +1,120 @@
package iamutil
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/hashicorp/errwrap"
"google.golang.org/api/googleapi"
)
type ApiHandle struct {
c *http.Client
userAgent string
}
func GetApiHandle(client *http.Client, userAgent string) *ApiHandle {
return &ApiHandle{
c: client,
userAgent: userAgent,
}
}
func (h *ApiHandle) DoGetRequest(ctx context.Context, r Resource, out interface{}) (err error) {
config := r.GetConfig()
req, err := constructRequest(r, &config.GetMethod, nil)
if err != nil {
return errwrap.Wrapf("Unable to construct Get request: {{err}}", err)
}
return h.doRequest(ctx, req, out)
}
func (h *ApiHandle) DoSetRequest(ctx context.Context, r Resource, data io.Reader, out interface{}) error {
config := r.GetConfig()
req, err := constructRequest(r, &config.SetMethod, data)
if err != nil {
return errwrap.Wrapf("Unable to construct Set request: {{err}}", err)
}
return h.doRequest(ctx, req, out)
}
func (h *ApiHandle) doRequest(ctx context.Context, req *http.Request, out interface{}) error {
if req.Header == nil {
req.Header = make(http.Header)
}
if h.userAgent != "" {
req.Header.Set("User-Agent", h.userAgent)
}
resp, err := h.c.Do(req.WithContext(ctx))
if err != nil {
return err
}
defer googleapi.CloseBody(resp)
if err := googleapi.CheckResponse(resp); err != nil {
return err
}
if err := json.NewDecoder(resp.Body).Decode(out); err != nil {
return errwrap.Wrapf("unable to decode JSON resp to output interface: {{err}}", err)
}
return nil
}
func constructRequest(r Resource, restMethod *RestMethod, data io.Reader) (*http.Request, error) {
config := r.GetConfig()
if data == nil && config != nil && config.Service == "cloudresourcemanager" {
// In order to support Resource Manager policies with conditional bindings,
// we need to request the policy version of 3. This request parameter is backwards compatible
// and will return version 1 policies if they are not yet updated to version 3.
requestPolicyVersion3 := `{"options": {"requestedPolicyVersion": 3}}`
data = strings.NewReader(requestPolicyVersion3)
}
req, err := http.NewRequest(
restMethod.HttpMethod,
googleapi.ResolveRelative(restMethod.BaseURL, restMethod.Path),
data)
if err != nil {
return nil, err
}
if req.Header == nil {
req.Header = make(http.Header)
}
if data != nil {
req.Header.Set("Content-Type", "application/json")
}
relId := r.GetRelativeId()
replacementMap := make(map[string]string)
if strings.Contains(restMethod.Path, "{+resource}") {
// +resource is used to represent full relative resource name
if len(config.Parameters) == 1 && config.Parameters[0] == "resource" {
relName := ""
tkns := strings.Split(config.TypeKey, "/")
for _, colId := range tkns {
if colName, ok := relId.IdTuples[colId]; ok {
relName += fmt.Sprintf("%s/%s/", colId, colName)
}
}
replacementMap["resource"] = strings.Trim(relName, "/")
}
} else {
for colId, resId := range relId.IdTuples {
rId, ok := config.CollectionReplacementKeys[colId]
if !ok {
return nil, fmt.Errorf("expected value for collection id %s", colId)
}
replacementMap[rId] = resId
}
}
googleapi.Expand(req.URL, replacementMap)
return req, nil
}

View File

@ -0,0 +1,142 @@
package iamutil
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-gcp-common/gcputil"
)
// NOTE: BigQuery does not conform to the typical REST for IAM policies
// instead it has an access array with bindings on the dataset
// object. https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets#Dataset
type AccessBinding struct {
Role string `json:"role,omitempty"`
UserByEmail string `json:"userByEmail,omitempty"`
GroupByEmail string `json:"groupByEmail,omitempty"`
}
type Dataset struct {
Access []*AccessBinding `json:"access,omitempty"`
Etag string `json:"etag,omitempty"`
}
// NOTE: DatasetResource implements IamResource.
// This is because bigquery datasets have their own
// ACLs instead of an IAM policy
type DatasetResource struct {
relativeId *gcputil.RelativeResourceName
config *RestResource
}
func (r *DatasetResource) GetConfig() *RestResource {
return r.config
}
func (r *DatasetResource) GetRelativeId() *gcputil.RelativeResourceName {
return r.relativeId
}
func (r *DatasetResource) GetIamPolicy(ctx context.Context, h *ApiHandle) (*Policy, error) {
var dataset Dataset
if err := h.DoGetRequest(ctx, r, &dataset); err != nil {
return nil, errwrap.Wrapf("unable to get BigQuery Dataset ACL: {{err}}", err)
}
p := datasetAsPolicy(&dataset)
return p, nil
}
func (r *DatasetResource) SetIamPolicy(ctx context.Context, h *ApiHandle, p *Policy) (*Policy, error) {
var jsonP []byte
ds, err := policyAsDataset(p)
if err != nil {
return nil, err
}
jsonP, err = json.Marshal(ds)
if err != nil {
return nil, err
}
reqJson := fmt.Sprintf(r.config.SetMethod.RequestFormat, jsonP)
if !json.Valid([]byte(reqJson)) {
return nil, fmt.Errorf("request format from generated BigQuery Dataset config invalid JSON: %s", reqJson)
}
var dataset Dataset
if err := h.DoSetRequest(ctx, r, strings.NewReader(reqJson), &dataset); err != nil {
return nil, errwrap.Wrapf("unable to set BigQuery Dataset ACL: {{err}}", err)
}
policy := datasetAsPolicy(&dataset)
return policy, nil
}
func policyAsDataset(p *Policy) (*Dataset, error) {
if p == nil {
return nil, errors.New("Policy cannot be nil")
}
ds := &Dataset{Etag: p.Etag}
for _, binding := range p.Bindings {
if binding.Condition != nil {
return nil, errors.New("Bigquery Datasets do not support conditional IAM")
}
for _, member := range binding.Members {
var email, iamType string
memberSplit := strings.Split(member, ":")
if len(memberSplit) == 2 {
iamType = memberSplit[0]
email = memberSplit[1]
} else {
email = member
}
if email != "" {
binding := &AccessBinding{Role: binding.Role}
if iamType == "group" {
binding.GroupByEmail = email
} else {
binding.UserByEmail = email
}
ds.Access = append(ds.Access, binding)
}
}
}
return ds, nil
}
func datasetAsPolicy(ds *Dataset) *Policy {
if ds == nil {
return &Policy{}
}
policy := &Policy{Etag: ds.Etag}
bindingMap := make(map[string]*Binding)
for _, accessBinding := range ds.Access {
var iamMember string
//NOTE: Can either have GroupByEmail or UserByEmail but not both
if accessBinding.GroupByEmail != "" {
iamMember = fmt.Sprintf("group:%s", accessBinding.GroupByEmail)
} else if strings.HasSuffix(accessBinding.UserByEmail, "gserviceaccount.com") {
iamMember = fmt.Sprintf("serviceAccount:%s", accessBinding.UserByEmail)
} else {
iamMember = fmt.Sprintf("user:%s", accessBinding.UserByEmail)
}
if binding, ok := bindingMap[accessBinding.Role]; ok {
binding.Members = append(binding.Members, iamMember)
} else {
bindingMap[accessBinding.Role] = &Binding{
Role: accessBinding.Role,
Members: []string{iamMember},
}
}
}
for _, v := range bindingMap {
policy.Bindings = append(policy.Bindings, v)
}
return policy
}

View File

@ -1,70 +0,0 @@
package iamutil
import (
"context"
"encoding/json"
"net/http"
"github.com/hashicorp/errwrap"
"google.golang.org/api/googleapi"
)
type IamHandle struct {
c *http.Client
userAgent string
}
func GetIamHandle(client *http.Client, userAgent string) *IamHandle {
return &IamHandle{
c: client,
userAgent: userAgent,
}
}
func (h *IamHandle) GetIamPolicy(ctx context.Context, r IamResource) (*Policy, error) {
req, err := r.GetIamPolicyRequest()
if err != nil {
return nil, errwrap.Wrapf("unable to construct GetIamPolicy request: {{err}}", err)
}
var p Policy
if err := h.doRequest(ctx, req, &p); err != nil {
return nil, errwrap.Wrapf("unable to get policy: {{err}}", err)
}
return &p, nil
}
func (h *IamHandle) SetIamPolicy(ctx context.Context, r IamResource, p *Policy) (*Policy, error) {
req, err := r.SetIamPolicyRequest(p)
if err != nil {
return nil, errwrap.Wrapf("unable to construct SetIamPolicy request: {{err}}", err)
}
var out Policy
if err := h.doRequest(ctx, req, &out); err != nil {
return nil, errwrap.Wrapf("unable to set policy: {{err}}", err)
}
return &out, nil
}
func (h *IamHandle) doRequest(ctx context.Context, req *http.Request, out interface{}) error {
if req.Header == nil {
req.Header = make(http.Header)
}
if h.userAgent != "" {
req.Header.Set("User-Agent", h.userAgent)
}
resp, err := h.c.Do(req.WithContext(ctx))
if err != nil {
return err
}
defer googleapi.CloseBody(resp)
if err := googleapi.CheckResponse(resp); err != nil {
return err
}
if err := json.NewDecoder(resp.Body).Decode(out); err != nil {
return errwrap.Wrapf("unable to decode JSON resp to output interface: {{err}}", err)
}
return nil
}

View File

@ -1,130 +1,49 @@
package iamutil
import (
"context"
"encoding/json"
"fmt"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-gcp-common/gcputil"
"google.golang.org/api/googleapi"
"io"
"net/http"
"strings"
)
// IamResource handles constructing HTTP requests for getting and
// setting IAM policies.
type IamResource interface {
GetIamPolicyRequest() (*http.Request, error)
SetIamPolicyRequest(*Policy) (req *http.Request, err error)
}
// parsedIamResource implements IamResource.
type parsedIamResource struct {
// IamResource implements Resource.
type IamResource struct {
relativeId *gcputil.RelativeResourceName
config *IamRestResource
config *RestResource
}
type IamRestResource struct {
// Name is the base name of the resource
// i.e. for a GCE instance: "instance"
Name string
// Type Key is the identifying path for the resource, or
// the RESTful resource identifier without resource IDs
// i.e. For a GCE instance: "projects/zones/instances"
TypeKey string
// Service Information
// Service is the name of the service this resource belongs to.
Service string
// IsPreferredVersion is true if this version of the API/resource is preferred.
IsPreferredVersion bool
// IsPreferredVersion is true if this version of the API/resource is preferred.
GetMethod RestMethod
// IsPreferredVersion is true if this version of the API/resource is preferred.
SetMethod RestMethod
// Ordered parameters to be replaced in method paths
Parameters []string
// collection Id --> parameter to be replaced {} name
CollectionReplacementKeys map[string]string
func (r *IamResource) GetConfig() *RestResource {
return r.config
}
type RestMethod struct {
HttpMethod string
BaseURL string
Path string
RequestFormat string
func (r *IamResource) GetRelativeId() *gcputil.RelativeResourceName {
return r.relativeId
}
func (r *parsedIamResource) SetIamPolicyRequest(p *Policy) (req *http.Request, err error) {
func (r *IamResource) GetIamPolicy(ctx context.Context, h *ApiHandle) (*Policy, error) {
var p Policy
if err := h.DoGetRequest(ctx, r, &p); err != nil {
return nil, errwrap.Wrapf("unable to get policy: {{err}}", err)
}
return &p, nil
}
func (r *IamResource) SetIamPolicy(ctx context.Context, h *ApiHandle, p *Policy) (*Policy, error) {
jsonP, err := json.Marshal(p)
if err != nil {
return nil, err
}
reqJson := fmt.Sprintf(r.config.SetMethod.RequestFormat, jsonP)
if !json.Valid([]byte(reqJson)) {
return nil, fmt.Errorf("request format from generated IAM config invalid JSON: %s", reqJson)
}
return r.constructRequest(&r.config.SetMethod, strings.NewReader(reqJson))
}
var requestPolicyVersion3 = `{"options": {"requestedPolicyVersion": 3}}`
func (r *parsedIamResource) GetIamPolicyRequest() (*http.Request, error) {
// In order to support Resource Manager policies with conditional bindings,
// we need to request the policy version of 3. This request parameter is backwards compatible
// and will return version 1 policies if they are not yet updated to version 3.
if r.config != nil && r.config.Service == "cloudresourcemanager" {
return r.constructRequest(&r.config.GetMethod, strings.NewReader(requestPolicyVersion3))
}
return r.constructRequest(&r.config.GetMethod, nil)
}
func (r *parsedIamResource) constructRequest(restMethod *RestMethod, data io.Reader) (*http.Request, error) {
req, err := http.NewRequest(
restMethod.HttpMethod,
googleapi.ResolveRelative(restMethod.BaseURL, restMethod.Path),
data)
if err != nil {
return nil, err
}
if req.Header == nil {
req.Header = make(http.Header)
}
if data != nil {
req.Header.Set("Content-Type", "application/json")
}
relId := r.relativeId
replacementMap := make(map[string]string)
if strings.Contains(restMethod.Path, "{+resource}") {
// +resource is used to represent full relative resource name
if len(r.config.Parameters) == 1 && r.config.Parameters[0] == "resource" {
relName := ""
tkns := strings.Split(r.config.TypeKey, "/")
for _, colId := range tkns {
relName += fmt.Sprintf("%s/%s/", colId, relId.IdTuples[colId])
}
replacementMap["resource"] = strings.Trim(relName, "/")
}
} else {
for colId, resId := range relId.IdTuples {
rId, ok := r.config.CollectionReplacementKeys[colId]
if !ok {
return nil, fmt.Errorf("expected value for collection id %s", colId)
}
replacementMap[rId] = resId
}
}
googleapi.Expand(req.URL, replacementMap)
return req, nil
var policy Policy
if err := h.DoSetRequest(ctx, r, strings.NewReader(reqJson), &policy); err != nil {
return nil, errwrap.Wrapf("unable to set policy: {{err}}", err)
}
return &policy, nil
}

View File

@ -0,0 +1,52 @@
package iamutil
import (
"context"
"github.com/hashicorp/go-gcp-common/gcputil"
)
// Resource handles constructing HTTP requests for getting and
// setting IAM policies.
type Resource interface {
GetIamPolicy(context.Context, *ApiHandle) (*Policy, error)
SetIamPolicy(context.Context, *ApiHandle, *Policy) (*Policy, error)
GetConfig() *RestResource
GetRelativeId() *gcputil.RelativeResourceName
}
type RestResource struct {
// Name is the base name of the resource
// i.e. for a GCE instance: "instance"
Name string
// TypeKey is the identifying path for the resource, or
// the RESTful resource identifier without resource IDs
// i.e. For a GCE instance: "projects/zones/instances"
TypeKey string
// Service is the name of the service this resource belongs to.
Service string
// IsPreferredVersion is true if this version of the API/resource is preferred.
IsPreferredVersion bool
// HTTP metadata for getting Policy data in GCP
GetMethod RestMethod
// HTTP metadata for setting Policy data in GCP
SetMethod RestMethod
// Ordered parameters to be replaced in method paths
Parameters []string
// Mapping of collection ids onto the parameter to be replaced
CollectionReplacementKeys map[string]string
}
type RestMethod struct {
HttpMethod string
BaseURL string
Path string
RequestFormat string
}

View File

@ -14,17 +14,17 @@ const (
errorMultipleVersions = `please provide a self-link with version instead; multiple versions of this resource exist, all non-preferred`
)
// IamResourceParser handles parsing resource ID and REST
// ResourceParser handles parsing resource ID and REST
// config from a given resource ID or name.
type IamResourceParser interface {
Parse(string) (IamResource, error)
type ResourceParser interface {
Parse(string) (Resource, error)
}
// GeneratedResources implements IamResourceParser - a value
// GeneratedResources implements ResourceParser - a value
// is generated using internal/generate_iam.go
type GeneratedResources map[string]map[string]map[string]IamRestResource
type GeneratedResources map[string]map[string]map[string]RestResource
func getResourceFromVersions(rawName string, versionMap map[string]IamRestResource) (*IamRestResource, error) {
func getResourceFromVersions(rawName string, versionMap map[string]RestResource) (*RestResource, error) {
possibleVer := make([]string, 0, len(versionMap))
for v, config := range versionMap {
if config.IsPreferredVersion || len(versionMap) == 1 {
@ -45,10 +45,10 @@ func getResourceFromVersions(rawName string, versionMap map[string]IamRestResour
return nil, fmt.Errorf(resourceParsingErrorTmpl, rawName, errorMultipleVersions)
}
func (apis GeneratedResources) GetRestConfig(rawName string, fullName *gcputil.FullResourceName, prefix string) (*IamRestResource, error) {
func (apis GeneratedResources) GetRestConfig(rawName string, fullName *gcputil.FullResourceName, prefix string) (*RestResource, error) {
relName := fullName.RelativeResourceName
if relName == nil {
return nil, fmt.Errorf(resourceParsingErrorTmpl, rawName, fmt.Errorf("unsupported resource type: %s", rawName))
return nil, fmt.Errorf(resourceParsingErrorTmpl, rawName, fmt.Errorf("relative name does not exist: %s", rawName))
}
serviceMap, ok := apis[relName.TypeKey]
@ -80,7 +80,7 @@ func (apis GeneratedResources) GetRestConfig(rawName string, fullName *gcputil.F
return nil, fmt.Errorf(resourceParsingErrorTmpl, rawName, errorMultipleServices)
}
func (apis GeneratedResources) Parse(rawName string) (IamResource, error) {
func (apis GeneratedResources) Parse(rawName string) (Resource, error) {
rUrl, err := url.Parse(rawName)
if err != nil {
return nil, fmt.Errorf(`resource "%s" is invalid URI`, rawName)
@ -123,8 +123,10 @@ func (apis GeneratedResources) Parse(rawName string) (IamResource, error) {
if err != nil {
return nil, err
}
return &parsedIamResource{
relativeId: relName,
config: cfg,
}, nil
switch cfg.TypeKey {
case "projects/dataset":
return &DatasetResource{relativeId: relName, config: cfg}, nil
default:
return &IamResource{relativeId: relName, config: cfg}, nil
}
}

View File

@ -236,7 +236,7 @@ func (b *backend) pathRoleSetDelete(ctx context.Context, req *logical.Request, d
return nil, err
}
iamHandle := iamutil.GetIamHandle(httpC, useragent.String())
apiHandle := iamutil.GetApiHandle(httpC, useragent.String())
warnings := make([]string, 0)
if rs.AccountId != nil {
@ -250,7 +250,7 @@ func (b *backend) pathRoleSetDelete(ctx context.Context, req *logical.Request, d
warnings = append(warnings, w)
}
if merr := b.removeBindings(ctx, iamHandle, rs.AccountId.EmailOrId, rs.Bindings); merr != nil {
if merr := b.removeBindings(ctx, apiHandle, rs.AccountId.EmailOrId, rs.Bindings); merr != nil {
for _, err := range merr.Errors {
w := fmt.Sprintf("unable to delete IAM policy bindings for service account %q (WAL entry to clean-up later has been added): %v", rs.AccountId.EmailOrId, err)
warnings = append(warnings, w)

View File

@ -137,7 +137,7 @@ func (b *backend) saveRoleSetWithNewAccount(ctx context.Context, s logical.Stora
return nil, err
}
iamHandle := iamutil.GetIamHandle(httpC, useragent.String())
apiHandle := iamutil.GetApiHandle(httpC, useragent.String())
oldAccount := rs.AccountId
oldBindings := rs.Bindings
@ -162,7 +162,7 @@ func (b *backend) saveRoleSetWithNewAccount(ctx context.Context, s logical.Stora
binds = newBinds
rs.Bindings = newBinds
}
walIds, err := rs.updateIamPolicies(ctx, s, b.iamResources, iamHandle, binds)
walIds, err := rs.updateIamPolicies(ctx, s, b.resources, apiHandle, binds)
if err != nil {
tryDeleteWALs(ctx, s, oldWals...)
return nil, err
@ -194,7 +194,7 @@ func (b *backend) saveRoleSetWithNewAccount(ctx context.Context, s logical.Stora
// Return any errors as warnings so user knows immediate cleanup failed
warnings := make([]string, 0)
if errs := b.removeBindings(ctx, iamHandle, oldAccount.EmailOrId, oldBindings); errs != nil {
if errs := b.removeBindings(ctx, apiHandle, oldAccount.EmailOrId, oldBindings); errs != nil {
warnings = make([]string, len(errs.Errors), len(errs.Errors)+2)
for idx, err := range errs.Errors {
warnings[idx] = fmt.Sprintf("unable to immediately delete old binding (WAL cleanup entry has been added): %v", err)
@ -358,7 +358,7 @@ func (rs *RoleSet) newKeyForTokenGen(ctx context.Context, s logical.Storage, iam
return walId, nil
}
func (rs *RoleSet) updateIamPolicies(ctx context.Context, s logical.Storage, enabledIamResources iamutil.IamResourceParser, iamHandle *iamutil.IamHandle, rb ResourceBindings) ([]string, error) {
func (rs *RoleSet) updateIamPolicies(ctx context.Context, s logical.Storage, enabledResources iamutil.ResourceParser, apiHandle *iamutil.ApiHandle, rb ResourceBindings) ([]string, error) {
wals := make([]string, 0, len(rb))
for rName, roles := range rb {
walId, err := framework.PutWAL(ctx, s, walTypeIamPolicy, &walIamPolicy{
@ -374,12 +374,12 @@ func (rs *RoleSet) updateIamPolicies(ctx context.Context, s logical.Storage, ena
return wals, err
}
resource, err := enabledIamResources.Parse(rName)
resource, err := enabledResources.Parse(rName)
if err != nil {
return wals, err
}
p, err := iamHandle.GetIamPolicy(ctx, resource)
p, err := resource.GetIamPolicy(ctx, apiHandle)
if err != nil {
return wals, err
}
@ -392,7 +392,7 @@ func (rs *RoleSet) updateIamPolicies(ctx context.Context, s logical.Storage, ena
continue
}
if _, err := iamHandle.SetIamPolicy(ctx, resource, newP); err != nil {
if _, err := resource.SetIamPolicy(ctx, apiHandle, newP); err != nil {
return wals, err
}
wals = append(wals, walId)

View File

@ -182,7 +182,7 @@ func (b *backend) serviceAccountPolicyRollback(ctx context.Context, req *logical
}
}
r, err := b.iamResources.Parse(entry.Resource)
r, err := b.resources.Parse(entry.Resource)
if err != nil {
return err
}
@ -192,12 +192,12 @@ func (b *backend) serviceAccountPolicyRollback(ctx context.Context, req *logical
return err
}
iamHandle := iamutil.GetIamHandle(httpC, useragent.String())
apiHandle := iamutil.GetApiHandle(httpC, useragent.String())
if err != nil {
return err
}
p, err := iamHandle.GetIamPolicy(ctx, r)
p, err := r.GetIamPolicy(ctx, apiHandle)
if err != nil {
return err
}
@ -212,7 +212,7 @@ func (b *backend) serviceAccountPolicyRollback(ctx context.Context, req *logical
return nil
}
_, err = iamHandle.SetIamPolicy(ctx, r, newP)
_, err = r.SetIamPolicy(ctx, apiHandle, newP)
return err
}
@ -240,15 +240,15 @@ func (b *backend) deleteTokenGenKey(ctx context.Context, iamAdmin *iam.Service,
return nil
}
func (b *backend) removeBindings(ctx context.Context, iamHandle *iamutil.IamHandle, email string, bindings ResourceBindings) (allErr *multierror.Error) {
func (b *backend) removeBindings(ctx context.Context, apiHandle *iamutil.ApiHandle, email string, bindings ResourceBindings) (allErr *multierror.Error) {
for resName, roles := range bindings {
resource, err := b.iamResources.Parse(resName)
resource, err := b.resources.Parse(resName)
if err != nil {
allErr = multierror.Append(allErr, errwrap.Wrapf(fmt.Sprintf("unable to delete role binding for resource '%s': {{err}}", resName), err))
continue
}
p, err := iamHandle.GetIamPolicy(ctx, resource)
p, err := resource.GetIamPolicy(ctx, apiHandle)
if err != nil {
allErr = multierror.Append(allErr, errwrap.Wrapf(fmt.Sprintf("unable to delete role binding for resource '%s': {{err}}", resName), err))
continue
@ -261,7 +261,7 @@ func (b *backend) removeBindings(ctx context.Context, iamHandle *iamutil.IamHand
if !changed {
continue
}
if _, err = iamHandle.SetIamPolicy(ctx, resource, newP); err != nil {
if _, err = resource.SetIamPolicy(ctx, apiHandle, newP); err != nil {
allErr = multierror.Append(allErr, errwrap.Wrapf(fmt.Sprintf("unable to delete role binding for resource '%s': {{err}}", resName), err))
continue
}

View File

@ -58,7 +58,7 @@ func pathSecretServiceAccountKey(b *backend) *framework.Path {
Description: fmt.Sprintf(`Private key type for service account key - defaults to %s"`, privateKeyTypeJson),
Default: privateKeyTypeJson,
},
"ttl": &framework.FieldSchema{
"ttl": {
Type: framework.TypeDurationSecond,
Description: "Lifetime of the service account key",
},
@ -215,6 +215,10 @@ func (b *backend) getSecretKey(ctx context.Context, s logical.Storage, rs *RoleS
resp := b.Secret(SecretTypeKey).Response(secretD, internalD)
resp.Secret.Renewable = true
resp.Secret.MaxTTL = cfg.MaxTTL
resp.Secret.TTL = cfg.TTL
// If the request came with a TTL value, overwrite the config default
if ttl > 0 {
resp.Secret.TTL = time.Duration(ttl) * time.Second
}

2
vendor/modules.txt vendored
View File

@ -442,7 +442,7 @@ github.com/hashicorp/vault-plugin-secrets-alicloud
github.com/hashicorp/vault-plugin-secrets-alicloud/clients
# github.com/hashicorp/vault-plugin-secrets-azure v0.5.6
github.com/hashicorp/vault-plugin-secrets-azure
# github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1
# github.com/hashicorp/vault-plugin-secrets-gcp v0.6.2
github.com/hashicorp/vault-plugin-secrets-gcp/plugin
github.com/hashicorp/vault-plugin-secrets-gcp/plugin/iamutil
github.com/hashicorp/vault-plugin-secrets-gcp/plugin/util