Skip to content

Commit

Permalink
VaultAuth: AWS auth support (hashicorp#235)
Browse files Browse the repository at this point in the history
Adds AWS auth support for iam type authentication. AWS credentials can
be specified as static, assumed from the EKS node role, assumed from
the EKS instance profile, or from an IRSA-enabled k8s service account.

To use an IRSA service account, the name must be specified in the
VaultAuth.Spec.AWS.IRSAServiceAccount field, and that service account
must have an eks.amazonaws.com/role-arn annotation with an IRSA
assumable role. A token requested from k8s for that service account
(with the default audience of sts.amazonaws.com) can then be used to
assume the specified AWS role and auth to Vault.

---------

Co-authored-by: Tom Proctor <[email protected]>
Co-authored-by: Ben Ash <[email protected]>
  • Loading branch information
3 people authored Jun 7, 2023
1 parent 3757f3a commit 91c8cd7
Show file tree
Hide file tree
Showing 24 changed files with 1,020 additions and 61 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Features:
* Helm: **Breaking Change**: Adds support for additional Auth Methods in the Transit auth method template: [GH-226](https://github.com/hashicorp/vault-secrets-operator/pull/226)
To migrate, set Kubernetes specific auth method configuration under `controller.manager.clientCache.storageEncryption`
using the new stanza `controller.manager.clientCache.storageEncryption.kubernetes`.
* VaultAuth: Adds support for the AWS authentication method, which can use an IRSA service account, static credentials in a Kubernetes secret, or the underlying node role/instance profile for authentication: [GH-234](https://github.com/hashicorp/vault-secrets-operator/pull/234)

Improvements:
* Extend vault Client validation checks to handle failed renewals: [GH-171](https://github.com/hashicorp/vault-secrets-operator/pull/171)
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ SKIP_CLEANUP ?=
# The number of k8s secrets to create in the VaultDynamicSecret's integration tests.
K8S_DB_SECRET_COUNT ?=

# Cloud test options
SKIP_AWS_TESTS ?= true
SKIP_AWS_STATIC_CREDS_TEST ?= true

# CHANNELS define the bundle channels used in the bundle.
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
Expand Down Expand Up @@ -246,12 +249,11 @@ ci-build: ## Build operator binary (without generating assets).
-o $(BUILD_DIR)/$(BIN_NAME) \
.

# TODO: this does not work on arm64 build machines.
.PHONY: ci-docker-build
ci-docker-build: ## Build docker image with the operator (without generating assets)
mkdir -p $(BUILD_DIR)/$(GOOS)/$(GOARCH)
cp $(BUILD_DIR)/$(BIN_NAME) $(BUILD_DIR)/$(GOOS)/$(GOARCH)/$(BIN_NAME)
docker build -t $(IMG) . --target release-default --build-arg GO_VERSION=$(shell cat .go-version)
docker build -t $(IMG) --platform $(GOOS)/$(GOARCH) . --target release-default --build-arg GO_VERSION=$(shell cat .go-version)

.PHONY: ci-test
ci-test: vet envtest ## Run tests in CI (without generating assets)
Expand All @@ -273,6 +275,7 @@ integration-test: set-image setup-vault ## Run integration tests for Vault OSS
OPERATOR_IMAGE_REPO=$(IMAGE_TAG_BASE) OPERATOR_IMAGE_TAG=$(VERSION) \
VAULT_OIDC_DISC_URL=$(VAULT_OIDC_DISC_URL) VAULT_OIDC_CA=$(VAULT_OIDC_CA) \
INTEGRATION_TESTS=true KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) K8S_CLUSTER_CONTEXT=$(K8S_CLUSTER_CONTEXT) CGO_ENABLED=0 \
SKIP_AWS_TESTS=$(SKIP_AWS_TESTS) SKIP_AWS_STATIC_CREDS_TEST=$(SKIP_AWS_STATIC_CREDS_TEST) \
go test github.com/hashicorp/vault-secrets-operator/test/integration/... $(TESTARGS) -timeout=30m

.PHONY: integration-test-helm
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,19 @@ make -f aws.mk build-push integration-test-eks
make -f aws.mk build-push integration-test-eks VAULT_ENTERPRISE=true ENT_TESTS=true
```

#### AWS auth test with static credentials

```shell
# Set SKIP_AWS_STATIC_CREDS_TEST=false and set the credentials for the static creds user via the environment variables TEST_AWS_ACCESS_KEY_ID,
# TEST_AWS_SECRET_ACCESS_KEY, TEST_AWS_STATIC_CREDS_ROLE (and TEST_AWS_SESSION_TOKEN if applicable) for a user in AWS.
# Note: these credentials will be set in a Kubernetes secret.
export TEST_AWS_ACCESS_KEY_ID="..."
export TEST_AWS_SECRET_ACCESS_KEY="..."
export TEST_AWS_SESSION_TOKEN="..."
export AWS_STATIC_CREDS_ROLE="arn:aws:iam::..."
make -f aws.mk integration-test-eks TESTARGS="-run TestVaultAuth" SKIP_AWS_STATIC_CREDS_TEST=false
```

### Integration Tests in GKE

```shell
Expand Down
38 changes: 37 additions & 1 deletion api/v1alpha1/vaultauth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,40 @@ type VaultAuthConfigAppRole struct {
SecretRef string `json:"secretRef"`
}

// VaultAuthConfigAWS provides VaultAuth configuration options needed for
// authenticating to Vault via an AWS AuthMethod. Will use creds from
// `SecretRef` or `IRSAServiceAccount` if provided, in that order. If neither
// are provided, the underlying node role or instance profile will be used to
// authenticate to Vault.
type VaultAuthConfigAWS struct {
// Vault role to use for authenticating
Role string `json:"role"`
// AWS Region to use for signing the authentication request
Region string `json:"region,omitempty"`
// The Vault header value to include in the STS signing request
HeaderValue string `json:"headerValue,omitempty"`

// The role session name to use when creating a webidentity provider
SessionName string `json:"sessionName,omitempty"`

// The STS endpoint to use; if not set will use the default
STSEndpoint string `json:"stsEndpoint,omitempty"`

// The IAM endpoint to use; if not set will use the default
IAMEndpoint string `json:"iamEndpoint,omitempty"`

// SecretRef is the name of a Kubernetes Secret which holds credentials for
// AWS. Expected keys include `access_key_id`, `secret_access_key`,
// `session_token`
SecretRef string `json:"secretRef,omitempty"`

// IRSAServiceAccount name to use with IAM Roles for Service Accounts
// (IRSA), and should be annotated with "eks.amazonaws.com/role-arn". This
// ServiceAccount will be checked for other EKS annotations:
// eks.amazonaws.com/audience and eks.amazonaws.com/token-expiration
IRSAServiceAccount string `json:"irsaServiceAccount,omitempty"`
}

// VaultAuthSpec defines the desired state of VaultAuth
type VaultAuthSpec struct {
// VaultConnectionRef of the corresponding VaultConnection CustomResource.
Expand All @@ -65,7 +99,7 @@ type VaultAuthSpec struct {
// Namespace to auth to in Vault
Namespace string `json:"namespace,omitempty"`
// Method to use when authenticating to Vault.
// +kubebuilder:validation:Enum=kubernetes;jwt;appRole
// +kubebuilder:validation:Enum=kubernetes;jwt;appRole;aws
Method string `json:"method"`
// Mount to use when authenticating to auth method.
Mount string `json:"mount"`
Expand All @@ -79,6 +113,8 @@ type VaultAuthSpec struct {
AppRole *VaultAuthConfigAppRole `json:"appRole,omitempty"`
// JWT specific auth configuration, requires that the Method be set to `jwt`.
JWT *VaultAuthConfigJWT `json:"jwt,omitempty"`
// AWS specific auth configuration, requires that Method be set to `aws`.
AWS *VaultAuthConfigAWS `json:"aws,omitempty"`
// StorageEncryption provides the necessary configuration to encrypt the client storage cache.
// This should only be configured when client cache persistence with encryption is enabled.
// This is done by passing setting the manager's commandline argument
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions aws.mk
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,20 @@ create-eks: ## Create a new EKS cluster
import-aws-vars:
-include $(TF_EKS_STATE_DIR)/outputs.env

# Currently only supports amd64
.PHONY: build-push
build-push: import-aws-vars ci-build ci-docker-build ## Build the operator image and push it to the GAR repository
aws ecr get-login-password --region $(AWS_REGION) | docker login --username AWS --password-stdin $(ECR_URL)
docker push $(IMG)

.PHONY: integration-test-eks
integration-test-eks: export SKIP_AWS_TESTS=false
integration-test-eks: export SKIP_AWS_STATIC_CREDS_TEST=true
integration-test-eks: build-push ## Run integration tests in the EKS cluster
aws eks --region $(AWS_REGION) update-kubeconfig --name $(EKS_CLUSTER_NAME)
$(MAKE) port-forward &
$(MAKE) integration-test K8S_CLUSTER_CONTEXT=$(K8S_CLUSTER_CONTEXT) IMAGE_TAG_BASE=$(IMAGE_TAG_BASE) \
IMG=$(IMG) VAULT_OIDC_DISC_URL=$(EKS_OIDC_URL) VAULT_OIDC_CA=false
IMG=$(IMG) VAULT_OIDC_DISC_URL=$(EKS_OIDC_URL) VAULT_OIDC_CA=false \
AWS_REGION=$(AWS_REGION) AWS_IRSA_ROLE=$(IRSA_ROLE) AWS_ACCOUNT_ID=$(ACCOUNT_ID)

.PHONY: destroy-ecr
destroy-ecr: ## Destroy the ECR repository
Expand Down
42 changes: 42 additions & 0 deletions chart/crds/secrets.hashicorp.com_vaultauths.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,47 @@ spec:
- roleId
- secretRef
type: object
aws:
description: AWS specific auth configuration, requires that Method
be set to `aws`.
properties:
headerValue:
description: The Vault header value to include in the STS signing
request
type: string
iamEndpoint:
description: The IAM endpoint to use; if not set will use the
default
type: string
irsaServiceAccount:
description: 'IRSAServiceAccount name to use with IAM Roles for
Service Accounts (IRSA), and should be annotated with "eks.amazonaws.com/role-arn".
This ServiceAccount will be checked for other EKS annotations:
eks.amazonaws.com/audience and eks.amazonaws.com/token-expiration'
type: string
region:
description: AWS Region to use for signing the authentication
request
type: string
role:
description: Vault role to use for authenticating
type: string
secretRef:
description: SecretRef is the name of a Kubernetes Secret which
holds credentials for AWS. Expected keys include `access_key_id`,
`secret_access_key`, `session_token`
type: string
sessionName:
description: The role session name to use when creating a webidentity
provider
type: string
stsEndpoint:
description: The STS endpoint to use; if not set will use the
default
type: string
required:
- role
type: object
headers:
additionalProperties:
type: string
Expand Down Expand Up @@ -126,6 +167,7 @@ spec:
- kubernetes
- jwt
- appRole
- aws
type: string
mount:
description: Mount to use when authenticating to auth method.
Expand Down
8 changes: 8 additions & 0 deletions chart/templates/manager-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ rules:
- get
- patch
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
Expand Down
42 changes: 42 additions & 0 deletions config/crd/bases/secrets.hashicorp.com_vaultauths.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,47 @@ spec:
- roleId
- secretRef
type: object
aws:
description: AWS specific auth configuration, requires that Method
be set to `aws`.
properties:
headerValue:
description: The Vault header value to include in the STS signing
request
type: string
iamEndpoint:
description: The IAM endpoint to use; if not set will use the
default
type: string
irsaServiceAccount:
description: 'IRSAServiceAccount name to use with IAM Roles for
Service Accounts (IRSA), and should be annotated with "eks.amazonaws.com/role-arn".
This ServiceAccount will be checked for other EKS annotations:
eks.amazonaws.com/audience and eks.amazonaws.com/token-expiration'
type: string
region:
description: AWS Region to use for signing the authentication
request
type: string
role:
description: Vault role to use for authenticating
type: string
secretRef:
description: SecretRef is the name of a Kubernetes Secret which
holds credentials for AWS. Expected keys include `access_key_id`,
`secret_access_key`, `session_token`
type: string
sessionName:
description: The role session name to use when creating a webidentity
provider
type: string
stsEndpoint:
description: The STS endpoint to use; if not set will use the
default
type: string
required:
- role
type: object
headers:
additionalProperties:
type: string
Expand Down Expand Up @@ -126,6 +167,7 @@ spec:
- kubernetes
- jwt
- appRole
- aws
type: string
mount:
description: Mount to use when authenticating to auth method.
Expand Down
8 changes: 8 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
Expand Down
1 change: 1 addition & 0 deletions controllers/vaultauth_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type VaultAuthReconciler struct {
//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch
// needed for managing cached Clients, duplicated in vaultconnection_controller.go
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;delete;update;patch;deletecollection
//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch

// Reconcile reconciles the secretsv1alpha1.VaultAuth resource.
// Each reconciliation will validate the resource's configuration
Expand Down
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ require (
github.com/go-logr/logr v1.2.4
github.com/google/uuid v1.3.0
github.com/gruntwork-io/terratest v0.42.0
github.com/hashicorp/go-hclog v1.5.0
github.com/hashicorp/go-rootcerts v1.0.2
github.com/hashicorp/go-secure-stdlib/awsutil v0.2.3-0.20230606170242-1a4b95565d57
github.com/hashicorp/golang-lru v0.5.4
github.com/hashicorp/vault/api v1.9.2
github.com/hashicorp/vault/sdk v0.9.1
Expand Down Expand Up @@ -44,14 +46,15 @@ require (
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
github.com/go-logr/zapr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-sql-driver/mysql v1.4.1 // indirect
github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
Expand Down Expand Up @@ -81,6 +84,8 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
Expand Down
Loading

0 comments on commit 91c8cd7

Please sign in to comment.