diff --git a/.circleci/config.yml b/.circleci/config.yml
index f9e59a9acfff..d1bd416b053e 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -9,11 +9,11 @@ jobs:
docker:
- image: docker.mirror.hashicorp.services/node:14-buster
shell: /usr/bin/env bash -euo pipefail -c
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
steps:
- checkout
- restore_cache:
- key: yarn-lock-v6-{{ checksum "ui/yarn.lock" }}
+ key: yarn-lock-v7-{{ checksum "ui/yarn.lock" }}
name: Restore yarn cache
- run:
command: |
@@ -22,7 +22,7 @@ jobs:
npm rebuild node-sass
name: Install UI dependencies
- save_cache:
- key: yarn-lock-v6-{{ checksum "ui/yarn.lock" }}
+ key: yarn-lock-v7-{{ checksum "ui/yarn.lock" }}
name: Save yarn cache
paths:
- ui/node_modules
@@ -30,7 +30,7 @@ jobs:
docker:
- image: docker.mirror.hashicorp.services/node:14-buster
shell: /usr/bin/env bash -euo pipefail -c
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
resource_class: xlarge
steps:
- run:
@@ -49,7 +49,7 @@ jobs:
working_directory: ~/
- checkout
- restore_cache:
- key: yarn-lock-v6-{{ checksum "ui/yarn.lock" }}
+ key: yarn-lock-v7-{{ checksum "ui/yarn.lock" }}
name: Restore yarn cache
- attach_workspace:
at: .
@@ -83,12 +83,12 @@ jobs:
docker:
- image: docker.mirror.hashicorp.services/node:14-buster
shell: /usr/bin/env bash -euo pipefail -c
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
resource_class: xlarge
steps:
- checkout
- restore_cache:
- key: yarn-lock-v6-{{ checksum "ui/yarn.lock" }}
+ key: yarn-lock-v7-{{ checksum "ui/yarn.lock" }}
name: Restore yarn cache
- attach_workspace:
at: .
@@ -101,7 +101,7 @@ jobs:
build-go-dev:
machine: true
shell: /usr/bin/env bash -euo pipefail -c
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
steps:
- run:
command: |
@@ -111,7 +111,7 @@ jobs:
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm -f "go${GO_VERSION}.linux-amd64.tar.gz"
- GOPATH="/go"
+ GOPATH="/home/circleci/go"
mkdir $GOPATH 2>/dev/null || { sudo mkdir $GOPATH && sudo chmod 777 $GOPATH; }
echo "export GOPATH='$GOPATH'" >> "$BASH_ENV"
echo "export PATH='$PATH:$GOPATH/bin:/usr/local/go/bin'" >> "$BASH_ENV"
@@ -125,7 +125,7 @@ jobs:
- checkout
- restore_cache:
keys:
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
name: Restore exact go modules cache
- attach_workspace:
at: .
@@ -145,7 +145,7 @@ jobs:
environment:
- CIRCLECI_CLI_VERSION: 0.1.5546
- GO_TAGS: ''
- - GO_VERSION: 1.17.2
+ - GO_VERSION: 1.17.5
- GOTESTSUM_VERSION: 0.5.2
algolia-index:
docker:
@@ -164,9 +164,9 @@ jobs:
name: Push content to Algolia Index
test-go-remote-docker:
docker:
- - image: docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster
+ - image: docker.mirror.hashicorp.services/cimg/go:1.17.5
resource_class: medium
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
parallelism: 8
steps:
- run:
@@ -199,7 +199,7 @@ jobs:
- go-test-cache-date-v1-{{ checksum "/tmp/go-cache-key" }}
- restore_cache:
keys:
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
name: Restore exact go modules cache
- run:
command: |
@@ -297,20 +297,20 @@ jobs:
-e NO_PROXY \
-e VAULT_TEST_LOG_DIR=/tmp/testlogs \
--network vaulttest --name \
- testcontainer docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster \
+ testcontainer docker.mirror.hashicorp.services/cimg/go:1.17.5 \
tail -f /dev/null
# Run tests
test -d /tmp/go-cache && docker cp /tmp/go-cache testcontainer:/tmp/gocache
- docker exec testcontainer sh -c 'mkdir -p /go/src/github.com/hashicorp/vault'
- docker cp . testcontainer:/go/src/github.com/hashicorp/vault/
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/src/github.com/hashicorp/vault'
+ docker cp . testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/
docker cp $DOCKER_CERT_PATH/ testcontainer:$DOCKER_CERT_PATH
# Copy the downloaded modules inside the container.
- docker exec testcontainer sh -c 'mkdir -p /go/pkg'
- docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/go/pkg/mod
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/pkg'
+ docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/home/circleci/go/pkg/mod
- docker exec -w /go/src/github.com/hashicorp/vault/ \
+ docker exec -w /home/circleci/go/src/github.com/hashicorp/vault/ \
-e CIRCLECI -e VAULT_CI_GO_TEST_RACE \
-e GOCACHE=/tmp/gocache \
-e GO_TAGS \
@@ -346,7 +346,7 @@ jobs:
no_output_timeout: 60m
- run:
command: |
- docker cp testcontainer:/go/src/github.com/hashicorp/vault/test-results .
+ docker cp testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/test-results .
docker cp testcontainer:/tmp/gocache /tmp/go-cache
name: Copy test results
when: always
@@ -361,9 +361,9 @@ jobs:
- GO_TAGS: ''
test-go-race:
docker:
- - image: docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster
+ - image: docker.mirror.hashicorp.services/cimg/go:1.17.5
resource_class: xlarge
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
parallelism: 8
steps:
- run:
@@ -393,7 +393,7 @@ jobs:
- go-test-cache-date-v1-{{ checksum "/tmp/go-cache-key" }}
- restore_cache:
keys:
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
name: Restore exact go modules cache
- run:
command: |
@@ -490,20 +490,20 @@ jobs:
-e NO_PROXY \
-e VAULT_TEST_LOG_DIR=/tmp/testlogs \
--network vaulttest --name \
- testcontainer docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster \
+ testcontainer docker.mirror.hashicorp.services/cimg/go:1.17.5 \
tail -f /dev/null
# Run tests
test -d /tmp/go-cache && docker cp /tmp/go-cache testcontainer:/tmp/gocache
- docker exec testcontainer sh -c 'mkdir -p /go/src/github.com/hashicorp/vault'
- docker cp . testcontainer:/go/src/github.com/hashicorp/vault/
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/src/github.com/hashicorp/vault'
+ docker cp . testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/
docker cp $DOCKER_CERT_PATH/ testcontainer:$DOCKER_CERT_PATH
# Copy the downloaded modules inside the container.
- docker exec testcontainer sh -c 'mkdir -p /go/pkg'
- docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/go/pkg/mod
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/pkg'
+ docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/home/circleci/go/pkg/mod
- docker exec -w /go/src/github.com/hashicorp/vault/ \
+ docker exec -w /home/circleci/go/src/github.com/hashicorp/vault/ \
-e CIRCLECI -e VAULT_CI_GO_TEST_RACE \
-e GOCACHE=/tmp/gocache \
-e GO_TAGS \
@@ -571,9 +571,9 @@ jobs:
name: Build Docker Image if Necessary
test-go:
docker:
- - image: docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster
+ - image: docker.mirror.hashicorp.services/cimg/go:1.17.5
resource_class: large
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
parallelism: 8
steps:
- run:
@@ -603,7 +603,7 @@ jobs:
- go-test-cache-date-v1-{{ checksum "/tmp/go-cache-key" }}
- restore_cache:
keys:
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
name: Restore exact go modules cache
- run:
command: |
@@ -700,20 +700,20 @@ jobs:
-e NO_PROXY \
-e VAULT_TEST_LOG_DIR=/tmp/testlogs \
--network vaulttest --name \
- testcontainer docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster \
+ testcontainer docker.mirror.hashicorp.services/cimg/go:1.17.5 \
tail -f /dev/null
# Run tests
test -d /tmp/go-cache && docker cp /tmp/go-cache testcontainer:/tmp/gocache
- docker exec testcontainer sh -c 'mkdir -p /go/src/github.com/hashicorp/vault'
- docker cp . testcontainer:/go/src/github.com/hashicorp/vault/
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/src/github.com/hashicorp/vault'
+ docker cp . testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/
docker cp $DOCKER_CERT_PATH/ testcontainer:$DOCKER_CERT_PATH
# Copy the downloaded modules inside the container.
- docker exec testcontainer sh -c 'mkdir -p /go/pkg'
- docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/go/pkg/mod
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/pkg'
+ docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/home/circleci/go/pkg/mod
- docker exec -w /go/src/github.com/hashicorp/vault/ \
+ docker exec -w /home/circleci/go/src/github.com/hashicorp/vault/ \
-e CIRCLECI -e VAULT_CI_GO_TEST_RACE \
-e GOCACHE=/tmp/gocache \
-e GO_TAGS \
@@ -759,7 +759,7 @@ jobs:
pre-flight-checks:
machine: true
shell: /usr/bin/env bash -euo pipefail -c
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
steps:
- run:
command: |
@@ -769,7 +769,7 @@ jobs:
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm -f "go${GO_VERSION}.linux-amd64.tar.gz"
- GOPATH="/go"
+ GOPATH="/home/circleci/go"
mkdir $GOPATH 2>/dev/null || { sudo mkdir $GOPATH && sudo chmod 777 $GOPATH; }
echo "export GOPATH='$GOPATH'" >> "$BASH_ENV"
echo "export PATH='$PATH:$GOPATH/bin:/usr/local/go/bin'" >> "$BASH_ENV"
@@ -810,9 +810,9 @@ jobs:
git config --global url."git@github.com:".insteadOf https://github.com/
- restore_cache:
keys:
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}
- - v1.3-{{checksum "go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}
name: Restore closest matching go modules cache
- run:
command: |
@@ -832,20 +832,20 @@ jobs:
}
name: Verify downloading modules did not modify any files
- save_cache:
- key: v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ key: v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
name: Save go modules cache
paths:
- - /go/pkg/mod
+ - /home/circleci/go/pkg/mod
environment:
- CIRCLECI_CLI_VERSION: 0.1.5546
- GO_TAGS: ''
- - GO_VERSION: 1.17.2
+ - GO_VERSION: 1.17.5
- GOTESTSUM_VERSION: 0.5.2
test-go-race-remote-docker:
docker:
- - image: docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster
+ - image: docker.mirror.hashicorp.services/cimg/go:1.17.5
resource_class: medium
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
parallelism: 8
steps:
- run:
@@ -878,7 +878,7 @@ jobs:
- go-test-cache-date-v1-{{ checksum "/tmp/go-cache-key" }}
- restore_cache:
keys:
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
name: Restore exact go modules cache
- run:
command: |
@@ -976,20 +976,20 @@ jobs:
-e NO_PROXY \
-e VAULT_TEST_LOG_DIR=/tmp/testlogs \
--network vaulttest --name \
- testcontainer docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster \
+ testcontainer docker.mirror.hashicorp.services/cimg/go:1.17.5 \
tail -f /dev/null
# Run tests
test -d /tmp/go-cache && docker cp /tmp/go-cache testcontainer:/tmp/gocache
- docker exec testcontainer sh -c 'mkdir -p /go/src/github.com/hashicorp/vault'
- docker cp . testcontainer:/go/src/github.com/hashicorp/vault/
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/src/github.com/hashicorp/vault'
+ docker cp . testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/
docker cp $DOCKER_CERT_PATH/ testcontainer:$DOCKER_CERT_PATH
# Copy the downloaded modules inside the container.
- docker exec testcontainer sh -c 'mkdir -p /go/pkg'
- docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/go/pkg/mod
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/pkg'
+ docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/home/circleci/go/pkg/mod
- docker exec -w /go/src/github.com/hashicorp/vault/ \
+ docker exec -w /home/circleci/go/src/github.com/hashicorp/vault/ \
-e CIRCLECI -e VAULT_CI_GO_TEST_RACE \
-e GOCACHE=/tmp/gocache \
-e GO_TAGS \
@@ -1025,7 +1025,7 @@ jobs:
no_output_timeout: 60m
- run:
command: |
- docker cp testcontainer:/go/src/github.com/hashicorp/vault/test-results .
+ docker cp testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/test-results .
docker cp testcontainer:/tmp/gocache /tmp/go-cache
name: Copy test results
when: always
diff --git a/.circleci/config/commands/@caches.yml b/.circleci/config/commands/@caches.yml
index 03e04cbc2bd4..97f5d3b44072 100644
--- a/.circleci/config/commands/@caches.yml
+++ b/.circleci/config/commands/@caches.yml
@@ -2,7 +2,7 @@ restore_yarn_cache:
steps:
- restore_cache:
name: Restore yarn cache
- key: &YARN_LOCK_CACHE_KEY yarn-lock-v6-{{ checksum "ui/yarn.lock" }}
+ key: &YARN_LOCK_CACHE_KEY yarn-lock-v7-{{ checksum "ui/yarn.lock" }}
save_yarn_cache:
steps:
- save_cache:
@@ -12,14 +12,15 @@ save_yarn_cache:
- ui/node_modules
# allows restoring go mod caches by incomplete prefix. This is useful when re-generating
# cache, but not when running builds and tests that require an exact match.
+# TODO should we be including arch in cache key?
restore_go_mod_cache_permissive:
steps:
- restore_cache:
name: Restore closest matching go modules cache
keys:
- - &gocachekey v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
- - v1.3-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}
- - v1.3-{{checksum "go.sum"}}
+ - &gocachekey v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}-{{checksum "api/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}-{{checksum "sdk/go.sum"}}
+ - v1.4-{{checksum "go.sum"}}
restore_go_mod_cache:
steps:
- restore_cache:
@@ -32,7 +33,7 @@ save_go_mod_cache:
name: Save go modules cache
key: *gocachekey
paths:
- - /go/pkg/mod
+ - /home/circleci/go/pkg/mod
refresh_go_mod_cache:
steps:
- restore_go_mod_cache_permissive
diff --git a/.circleci/config/commands/go_test.yml b/.circleci/config/commands/go_test.yml
index 6ea817b12218..ca3f71f0d2a4 100644
--- a/.circleci/config/commands/go_test.yml
+++ b/.circleci/config/commands/go_test.yml
@@ -14,7 +14,7 @@ parameters:
default: false
go_image:
type: string
- default: "docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster"
+ default: "docker.mirror.hashicorp.services/cimg/go:1.17.5"
use_docker:
type: boolean
default: false
@@ -139,15 +139,15 @@ steps:
# Run tests
test -d << parameters.cache_dir >> && docker cp << parameters.cache_dir >> testcontainer:/tmp/gocache
- docker exec testcontainer sh -c 'mkdir -p /go/src/github.com/hashicorp/vault'
- docker cp . testcontainer:/go/src/github.com/hashicorp/vault/
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/src/github.com/hashicorp/vault'
+ docker cp . testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/
docker cp $DOCKER_CERT_PATH/ testcontainer:$DOCKER_CERT_PATH
# Copy the downloaded modules inside the container.
- docker exec testcontainer sh -c 'mkdir -p /go/pkg'
- docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/go/pkg/mod
+ docker exec testcontainer sh -c 'mkdir -p /home/circleci/go/pkg'
+ docker cp "$(go env GOPATH)/pkg/mod" testcontainer:/home/circleci/go/pkg/mod
- docker exec -w /go/src/github.com/hashicorp/vault/ \
+ docker exec -w /home/circleci/go/src/github.com/hashicorp/vault/ \
-e CIRCLECI -e VAULT_CI_GO_TEST_RACE \
-e GOCACHE=/tmp/gocache \
-e GO_TAGS \
@@ -185,7 +185,7 @@ steps:
name: Copy test results
when: always
command: |
- docker cp testcontainer:/go/src/github.com/hashicorp/vault/test-results .
+ docker cp testcontainer:/home/circleci/go/src/github.com/hashicorp/vault/test-results .
docker cp testcontainer:/tmp/gocache << parameters.cache_dir >>
- when:
condition: << parameters.save_cache >>
diff --git a/.circleci/config/commands/setup-go.yml b/.circleci/config/commands/setup-go.yml
index b7c515910517..a06d2f1099f3 100644
--- a/.circleci/config/commands/setup-go.yml
+++ b/.circleci/config/commands/setup-go.yml
@@ -22,7 +22,7 @@ steps:
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm -f "go${GO_VERSION}.linux-amd64.tar.gz"
- GOPATH="/go"
+ GOPATH="/home/circleci/go"
mkdir $GOPATH 2>/dev/null || { sudo mkdir $GOPATH && sudo chmod 777 $GOPATH; }
echo "export GOPATH='$GOPATH'" >> "$BASH_ENV"
echo "export PATH='$PATH:$GOPATH/bin:/usr/local/go/bin'" >> "$BASH_ENV"
diff --git a/.circleci/config/executors/@executors.yml b/.circleci/config/executors/@executors.yml
index 5cf5d8fcf879..092349046de1 100644
--- a/.circleci/config/executors/@executors.yml
+++ b/.circleci/config/executors/@executors.yml
@@ -3,46 +3,46 @@ go-machine:
shell: /usr/bin/env bash -euo pipefail -c
environment:
CIRCLECI_CLI_VERSION: 0.1.5546 # Pin CircleCI CLI to patch version (ex: 1.2.3)
- GO_VERSION: 1.17.2 # Pin Go to patch version (ex: 1.2.3)
+ GO_VERSION: 1.17.5 # Pin Go to patch version (ex: 1.2.3)
GOTESTSUM_VERSION: 0.5.2 # Pin gotestsum to patch version (ex: 1.2.3)
GO_TAGS: ""
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
node:
docker:
- image: docker.mirror.hashicorp.services/node:14-buster
shell: /usr/bin/env bash -euo pipefail -c
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
python:
docker:
- image: docker.mirror.hashicorp.services/python:3-alpine
shell: /usr/bin/env bash -euo pipefail -c
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
alpine:
docker:
- image: docker.mirror.hashicorp.services/alpine:3.13
shell: /bin/sh
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
docker-env-go-test-remote-docker:
resource_class: medium
docker:
- - image: "docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster"
+ - image: "docker.mirror.hashicorp.services/cimg/go:1.17.5"
environment:
CIRCLECI_CLI_VERSION: 0.1.5546 # Pin CircleCI CLI to patch version (ex: 1.2.3)
GO_TAGS: ""
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
docker-env-go-test:
resource_class: large
docker:
- - image: "docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster"
+ - image: "docker.mirror.hashicorp.services/cimg/go:1.17.5"
environment:
CIRCLECI_CLI_VERSION: 0.1.5546 # Pin CircleCI CLI to patch version (ex: 1.2.3)
GO_TAGS: ""
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
docker-env-go-test-race:
resource_class: xlarge
docker:
- - image: "docker.mirror.hashicorp.services/circleci/golang:1.17.2-buster"
+ - image: "docker.mirror.hashicorp.services/cimg/go:1.17.5"
environment:
CIRCLECI_CLI_VERSION: 0.1.5546 # Pin CircleCI CLI to patch version (ex: 1.2.3)
GO_TAGS: ""
- working_directory: /go/src/github.com/hashicorp/vault
+ working_directory: /home/circleci/go/src/github.com/hashicorp/vault
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b369521d202d..7132605cdd78 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -50,7 +50,7 @@ jobs:
matrix:
goos: [ freebsd, windows, netbsd, openbsd, solaris ]
goarch: [ "386", "amd64", "arm" ]
- go: [ "1.17.2" ]
+ go: [ "1.17.5" ]
exclude:
- goos: solaris
goarch: 386
@@ -102,7 +102,7 @@ jobs:
matrix:
goos: [linux]
goarch: ["arm", "arm64", "386", "amd64"]
- go: ["1.17.2"]
+ go: ["1.17.5"]
fail-fast: true
name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build
@@ -179,7 +179,7 @@ jobs:
matrix:
goos: [ darwin ]
goarch: [ "amd64", "arm64" ]
- go: [ "1.17.2" ]
+ go: [ "1.17.5" ]
fail-fast: true
name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build
steps:
@@ -239,4 +239,4 @@ jobs:
zip_artifact_name: ${{ env.PKG_NAME }}_${{ needs.get-product-version.outputs.product-version }}_linux_${{ matrix.arch }}.zip
tags: |
docker.io/hashicorp/${{env.repo}}:${{env.version}}
- ecr.public.aws/hashicorp/${{env.repo}}:${{env.version}}
+ public.ecr.aws/hashicorp/${{env.repo}}:${{env.version}}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6ea78fcece1..cc1e3a21a171 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,34 @@
+## 1.10.0
+### Unreleased
+
+Changelog preview coming soon!
+
+## 1.9.1
+### December 9, 2021
+
+IMPROVEMENTS:
+
+* storage/aerospike: Upgrade `aerospike-client-go` to v5.6.0. [[GH-12165](https://github.com/hashicorp/vault/pull/12165)]
+
+BUG FIXES:
+
+* auth/approle: Fix regression where unset cidrlist is returned as nil instead of zero-length array. [[GH-13235](https://github.com/hashicorp/vault/pull/13235)]
+* ha (enterprise): Prevents performance standby nodes from serving and caching stale data immediately after performance standby election completes
+* http:Fix /sys/monitor endpoint returning streaming not supported [[GH-13200](https://github.com/hashicorp/vault/pull/13200)]
+* identity/oidc: Make the `nonce` parameter optional for the Authorization Endpoint of OIDC providers. [[GH-13231](https://github.com/hashicorp/vault/pull/13231)]
+* identity: Fixes a panic in the OIDC key rotation due to a missing nil check. [[GH-13298](https://github.com/hashicorp/vault/pull/13298)]
+* sdk/queue: move lock before length check to prevent panics. [[GH-13146](https://github.com/hashicorp/vault/pull/13146)]
+* secrets/azure: Fixes service principal generation when assigning roles that have [DataActions](https://docs.microsoft.com/en-us/azure/role-based-access-control/role-definitions#dataactions). [[GH-13277](https://github.com/hashicorp/vault/pull/13277)]
+* secrets/pki: Recognize ed25519 when requesting a response in PKCS8 format [[GH-13257](https://github.com/hashicorp/vault/pull/13257)]
+* storage/raft: Fix a panic when trying to store a key > 32KB in a transaction. [[GH-13286](https://github.com/hashicorp/vault/pull/13286)]
+* storage/raft: Fix a panic when trying to write a key > 32KB [[GH-13282](https://github.com/hashicorp/vault/pull/13282)]
+* ui: Do not show verify connection value on database connection config page [[GH-13152](https://github.com/hashicorp/vault/pull/13152)]
+* ui: Fixes issue restoring raft storage snapshot [[GH-13107](https://github.com/hashicorp/vault/pull/13107)]
+* ui: Fixes issue with OIDC auth workflow when using MetaMask Chrome extension [[GH-13133](https://github.com/hashicorp/vault/pull/13133)]
+* ui: Fixes issue with automate secret deletion value not displaying initially if set in secret metadata edit view [[GH-13177](https://github.com/hashicorp/vault/pull/13177)]
+* ui: Fixes issue with placeholder not displaying for automatically deleted secrets when deletion time has passed [[GH-13166](https://github.com/hashicorp/vault/pull/13166)]
+* ui: Fixes node-forge error when parsing EC (elliptical curve) certs [[GH-13238](https://github.com/hashicorp/vault/pull/13238)]
+
## 1.9.0
### November 17, 2021
@@ -198,6 +229,24 @@ of dirty pages in the merkle tree at time of checkpoint creation. [[GH-2093](htt
* ui: update bar chart when model changes [[GH-12622](https://github.com/hashicorp/vault/pull/12622)]
* ui: updating database TTL picker help text. [[GH-12212](https://github.com/hashicorp/vault/pull/12212)]
+## 1.8.6
+### December 9, 2021
+
+CHANGES:
+
+* go: Update go version to 1.16.9 [[GH-13029](https://github.com/hashicorp/vault/pull/13029)]
+
+BUG FIXES:
+
+* ha (enterprise): Prevents performance standby nodes from serving and caching stale data immediately after performance standby election completes
+* storage/raft: Fix a panic when trying to store a key > 32KB in a transaction. [[GH-13286](https://github.com/hashicorp/vault/pull/13286)]
+* storage/raft: Fix a panic when trying to write a key > 32KB [[GH-13282](https://github.com/hashicorp/vault/pull/13282)]
+* ui: Adds pagination to auth methods list view [[GH-13054](https://github.com/hashicorp/vault/pull/13054)]
+* ui: Do not show verify connection value on database connection config page [[GH-13152](https://github.com/hashicorp/vault/pull/13152)]
+* ui: Fixes issue restoring raft storage snapshot [[GH-13107](https://github.com/hashicorp/vault/pull/13107)]
+* ui: Fixes issue with OIDC auth workflow when using MetaMask Chrome extension [[GH-13133](https://github.com/hashicorp/vault/pull/13133)]
+* ui: Fixes issue with the number of PGP Key inputs not matching the key shares number in the initialization form on change [[GH-13038](https://github.com/hashicorp/vault/pull/13038)]
+
## 1.8.5
### November 4, 2021
@@ -459,6 +508,18 @@ BUG FIXES:
* ui: fix issue where select-one option was not showing in secrets database role creation [[GH-11294](https://github.com/hashicorp/vault/pull/11294)]
* ui: fix oidc login with Safari [[GH-11884](https://github.com/hashicorp/vault/pull/11884)]
+## 1.7.7
+### December 9, 2021
+
+BUG FIXES:
+
+* ha (enterprise): Prevents performance standby nodes from serving and caching stale data immediately after performance standby election completes
+* storage/raft: Fix a panic when trying to store a key > 32KB in a transaction. [[GH-13286](https://github.com/hashicorp/vault/pull/13286)]
+* storage/raft: Fix a panic when trying to write a key > 32KB [[GH-13282](https://github.com/hashicorp/vault/pull/13282)]
+* ui: Fixes issue restoring raft storage snapshot [[GH-13107](https://github.com/hashicorp/vault/pull/13107)]
+* ui: Fixes issue with OIDC auth workflow when using MetaMask Chrome extension [[GH-13133](https://github.com/hashicorp/vault/pull/13133)]
+* ui: Fixes issue with the number of PGP Key inputs not matching the key shares number in the initialization form on change [[GH-13038](https://github.com/hashicorp/vault/pull/13038)]
+
## 1.7.6
### November 4, 2021
diff --git a/Makefile b/Makefile
index 233b081ea49c..01a50c82a079 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ EXTERNAL_TOOLS=\
GOFMT_FILES?=$$(find . -name '*.go' | grep -v pb.go | grep -v vendor)
-GO_VERSION_MIN=1.17.2
+GO_VERSION_MIN=1.17.5
GO_CMD?=go
CGO_ENABLED?=0
ifneq ($(FDB_ENABLED), )
diff --git a/README.md b/README.md
index a871940d1c21..14c85eb77226 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ Developing Vault
If you wish to work on Vault itself or any of its built-in systems, you'll
first need [Go](https://www.golang.org) installed on your machine. Go version
-1.17.2+ is *required*.
+1.17.5+ is *required*.
For local dev first make sure Go is properly installed, including setting up a
[GOPATH](https://golang.org/doc/code.html#GOPATH). Ensure that `$GOPATH/bin` is in
diff --git a/builtin/credential/github/backend_test.go b/builtin/credential/github/backend_test.go
index 4e51eedba855..f3360f52cfb5 100644
--- a/builtin/credential/github/backend_test.go
+++ b/builtin/credential/github/backend_test.go
@@ -2,6 +2,7 @@ package github
import (
"context"
+ "errors"
"fmt"
"os"
"strings"
@@ -70,6 +71,9 @@ func testLoginWrite(t *testing.T, d map[string]interface{}, expectedTTL time.Dur
ErrorOk: true,
Data: d,
Check: func(resp *logical.Response) error {
+ if resp == nil {
+ return errors.New("expected a response but got nil")
+ }
if resp.IsError() && expectFail {
return nil
}
diff --git a/builtin/credential/github/path_config.go b/builtin/credential/github/path_config.go
index 54b2b3d9d097..84c03d3dbb79 100644
--- a/builtin/credential/github/path_config.go
+++ b/builtin/credential/github/path_config.go
@@ -7,6 +7,7 @@ import (
"strings"
"time"
+ "github.com/google/go-github/github"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/tokenutil"
"github.com/hashicorp/vault/sdk/logical"
@@ -19,8 +20,12 @@ func pathConfig(b *backend) *framework.Path {
"organization": {
Type: framework.TypeString,
Description: "The organization users must be part of",
+ Required: true,
+ },
+ "organization_id": {
+ Type: framework.TypeInt64,
+ Description: "The ID of the organization users must be part of",
},
-
"base_url": {
Type: framework.TypeString,
Description: `The API endpoint to use. Useful if you
@@ -55,6 +60,7 @@ API-compatible authentication server.`,
}
func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
+ var resp logical.Response
c, err := b.Config(ctx, req.Storage)
if err != nil {
return nil, err
@@ -66,19 +72,47 @@ func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, dat
if organizationRaw, ok := data.GetOk("organization"); ok {
c.Organization = organizationRaw.(string)
}
+ if c.Organization == "" {
+ return logical.ErrorResponse("organization is a required parameter"), nil
+ }
+ if organizationRaw, ok := data.GetOk("organization_id"); ok {
+ c.OrganizationID = organizationRaw.(int64)
+ }
+
+ var parsedURL *url.URL
if baseURLRaw, ok := data.GetOk("base_url"); ok {
baseURL := baseURLRaw.(string)
- _, err := url.Parse(baseURL)
- if err != nil {
- return logical.ErrorResponse(fmt.Sprintf("Error parsing given base_url: %s", err)), nil
- }
if !strings.HasSuffix(baseURL, "/") {
baseURL += "/"
}
+ parsedURL, err = url.Parse(baseURL)
+ if err != nil {
+ return logical.ErrorResponse(fmt.Sprintf("error parsing given base_url: %s", err)), nil
+ }
c.BaseURL = baseURL
}
+ if c.OrganizationID == 0 {
+ client, err := b.Client("")
+ if err != nil {
+ return nil, err
+ }
+ // ensure our client has the BaseURL if it was provided
+ if parsedURL != nil {
+ client.BaseURL = parsedURL
+ }
+
+ // we want to set the Org ID in the config so we can use that to verify
+ // the credentials on login
+ err = c.setOrganizationID(ctx, client)
+ if err != nil {
+ errorMsg := fmt.Errorf("unable to fetch the organization_id, you must manually set it in the config: %s", err)
+ b.Logger().Error(errorMsg.Error())
+ return nil, errorMsg
+ }
+ }
+
if err := c.ParseTokenFields(req, data); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
@@ -103,7 +137,11 @@ func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, dat
return nil, err
}
- return nil, nil
+ if len(resp.Warnings) == 0 {
+ return nil, nil
+ }
+
+ return &resp, nil
}
func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
@@ -116,8 +154,9 @@ func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, data
}
d := map[string]interface{}{
- "organization": config.Organization,
- "base_url": config.BaseURL,
+ "organization_id": config.OrganizationID,
+ "organization": config.Organization,
+ "base_url": config.BaseURL,
}
config.PopulateTokenData(d)
@@ -163,8 +202,25 @@ func (b *backend) Config(ctx context.Context, s logical.Storage) (*config, error
type config struct {
tokenutil.TokenParams
- Organization string `json:"organization" structs:"organization" mapstructure:"organization"`
- BaseURL string `json:"base_url" structs:"base_url" mapstructure:"base_url"`
- TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"`
- MaxTTL time.Duration `json:"max_ttl" structs:"max_ttl" mapstructure:"max_ttl"`
+ OrganizationID int64 `json:"organization_id" structs:"organization_id" mapstructure:"organization_id"`
+ Organization string `json:"organization" structs:"organization" mapstructure:"organization"`
+ BaseURL string `json:"base_url" structs:"base_url" mapstructure:"base_url"`
+ TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"`
+ MaxTTL time.Duration `json:"max_ttl" structs:"max_ttl" mapstructure:"max_ttl"`
+}
+
+func (c *config) setOrganizationID(ctx context.Context, client *github.Client) error {
+ org, _, err := client.Organizations.Get(ctx, c.Organization)
+ if err != nil {
+ return err
+ }
+
+ orgID := org.GetID()
+ if orgID == 0 {
+ return fmt.Errorf("organization_id not found for %s", c.Organization)
+ }
+
+ c.OrganizationID = orgID
+
+ return nil
}
diff --git a/builtin/credential/github/path_config_test.go b/builtin/credential/github/path_config_test.go
new file mode 100644
index 000000000000..e8d0cf5fdb39
--- /dev/null
+++ b/builtin/credential/github/path_config_test.go
@@ -0,0 +1,214 @@
+package github
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/vault/sdk/logical"
+ "github.com/stretchr/testify/assert"
+)
+
+func createBackendWithStorage(t *testing.T) (*backend, logical.Storage) {
+ t.Helper()
+ config := logical.TestBackendConfig()
+ config.StorageView = &logical.InmemStorage{}
+
+ b := Backend()
+ if b == nil {
+ t.Fatalf("failed to create backend")
+ }
+ err := b.Backend.Setup(context.Background(), config)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return b, config.StorageView
+}
+
+// setupTestServer configures httptest server to intercept and respond to the
+// request to base_url
+func setupTestServer(t *testing.T) *httptest.Server {
+ t.Helper()
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ var resp string
+ if strings.Contains(r.URL.String(), "/user/orgs") {
+ resp = string(listOrgResponse)
+ } else if strings.Contains(r.URL.String(), "/user/teams") {
+ resp = string(listUserTeamsResponse)
+ } else if strings.Contains(r.URL.String(), "/user") {
+ resp = getUserResponse
+ } else if strings.Contains(r.URL.String(), "/orgs/") {
+ resp = getOrgResponse
+ }
+
+ w.Header().Add("Content-Type", "application/json")
+ fmt.Fprintln(w, resp)
+ }))
+}
+
+// TestGitHub_WriteReadConfig tests that we can successfully read and write
+// the github auth config
+func TestGitHub_WriteReadConfig(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+
+ // use a test server to return our mock GH org info
+ ts := setupTestServer(t)
+ defer ts.Close()
+
+ // Write the config
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.UpdateOperation,
+ Data: map[string]interface{}{
+ "organization": "foo-org",
+ "base_url": ts.URL, // base_url will call the test server
+ },
+ Storage: s,
+ })
+ assert.NoError(t, err)
+ assert.Nil(t, resp)
+ assert.NoError(t, resp.Error())
+
+ // Read the config
+ resp, err = b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.ReadOperation,
+ Storage: s,
+ })
+ assert.NoError(t, err)
+ assert.NoError(t, resp.Error())
+
+ // the ID should be set, we grab it from the GET /orgs API
+ assert.Equal(t, int64(12345), resp.Data["organization_id"])
+ assert.Equal(t, "foo-org", resp.Data["organization"])
+}
+
+// TestGitHub_WriteReadConfig_OrgID tests that we can successfully read and
+// write the github auth config with an organization_id param
+func TestGitHub_WriteReadConfig_OrgID(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+
+ // Write the config and pass in organization_id
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.UpdateOperation,
+ Data: map[string]interface{}{
+ "organization": "foo-org",
+ "organization_id": 98765,
+ },
+ Storage: s,
+ })
+ assert.NoError(t, err)
+ assert.Nil(t, resp)
+ assert.NoError(t, resp.Error())
+
+ // Read the config
+ resp, err = b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.ReadOperation,
+ Storage: s,
+ })
+ assert.NoError(t, err)
+ assert.NoError(t, resp.Error())
+
+ // the ID should be set to what was written in the config
+ assert.Equal(t, int64(98765), resp.Data["organization_id"])
+ assert.Equal(t, "foo-org", resp.Data["organization"])
+}
+
+// TestGitHub_ErrorNoOrgID tests that an error is returned when we cannot fetch
+// the org ID for the given org name
+func TestGitHub_ErrorNoOrgID(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+ // use a test server to return our mock GH org info
+ ts := func() *httptest.Server {
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Add("Content-Type", "application/json")
+ resp := `{ "id": 0 }`
+ fmt.Fprintln(w, resp)
+ }))
+ }
+
+ defer ts().Close()
+
+ // Write the config
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.UpdateOperation,
+ Data: map[string]interface{}{
+ "organization": "foo-org",
+ "base_url": ts().URL, // base_url will call the test server
+ },
+ Storage: s,
+ })
+ assert.Error(t, err)
+ assert.Nil(t, resp)
+ assert.Equal(t, errors.New(
+ "unable to fetch the organization_id, you must manually set it in the config: organization_id not found for foo-org",
+ ), err)
+}
+
+// TestGitHub_WriteConfig_ErrorNoOrg tests that an error is returned when the
+// required "organization" parameter is not provided
+func TestGitHub_WriteConfig_ErrorNoOrg(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+
+ // Write the config
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.UpdateOperation,
+ Data: map[string]interface{}{},
+ Storage: s,
+ })
+
+ assert.NoError(t, err)
+ assert.Error(t, resp.Error())
+ assert.Equal(t, errors.New("organization is a required parameter"), resp.Error())
+}
+
+// https://docs.github.com/en/rest/reference/users#get-the-authenticated-user
+// Note: many of the fields have been omitted
+var getUserResponse = `
+{
+ "login": "user-foo",
+ "id": 6789,
+ "description": "A great user. The very best user.",
+ "name": "foo name",
+ "company": "foo-company",
+ "type": "User"
+}
+`
+
+// https://docs.github.com/en/rest/reference/orgs#get-an-organization
+// Note: many of the fields have been omitted, we only care about 'login' and 'id'
+var getOrgResponse = `
+{
+ "login": "foo-org",
+ "id": 12345,
+ "description": "A great org. The very best org.",
+ "name": "foo-display-name",
+ "company": "foo-company",
+ "type": "Organization"
+}
+`
+
+// https://docs.github.com/en/rest/reference/orgs#list-organizations-for-the-authenticated-user
+var listOrgResponse = []byte(fmt.Sprintf(`[%v]`, getOrgResponse))
+
+// https://docs.github.com/en/rest/reference/teams#list-teams-for-the-authenticated-user
+// Note: many of the fields have been omitted
+var listUserTeamsResponse = []byte(fmt.Sprintf(`[
+{
+ "id": 1,
+ "node_id": "MDQ6VGVhbTE=",
+ "name": "Foo team",
+ "slug": "foo-team",
+ "description": "A great team. The very best team.",
+ "permission": "admin",
+ "organization": %v
+ }
+]`, getOrgResponse))
diff --git a/builtin/credential/github/path_login.go b/builtin/credential/github/path_login.go
index 68070e4829bd..252b5641cd4f 100644
--- a/builtin/credential/github/path_login.go
+++ b/builtin/credential/github/path_login.go
@@ -2,9 +2,9 @@ package github
import (
"context"
+ "errors"
"fmt"
"net/url"
- "strings"
"github.com/google/go-github/github"
"github.com/hashicorp/vault/sdk/framework"
@@ -33,16 +33,13 @@ func pathLogin(b *backend) *framework.Path {
func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
token := data.Get("token").(string)
- var verifyResp *verifyCredentialsResp
- if verifyResponse, resp, err := b.verifyCredentials(ctx, req, token); err != nil {
+ verifyResp, err := b.verifyCredentials(ctx, req, token)
+ if err != nil {
return nil, err
- } else if resp != nil {
- return resp, nil
- } else {
- verifyResp = verifyResponse
}
return &logical.Response{
+ Warnings: verifyResp.Warnings,
Auth: &logical.Auth{
Alias: &logical.Alias{
Name: *verifyResp.User.Login,
@@ -54,13 +51,9 @@ func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Requ
func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
token := data.Get("token").(string)
- var verifyResp *verifyCredentialsResp
- if verifyResponse, resp, err := b.verifyCredentials(ctx, req, token); err != nil {
+ verifyResp, err := b.verifyCredentials(ctx, req, token)
+ if err != nil {
return nil, err
- } else if resp != nil {
- return resp, nil
- } else {
- verifyResp = verifyResponse
}
auth := &logical.Auth{
@@ -84,7 +77,8 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *fra
}
resp := &logical.Response{
- Auth: auth,
+ Warnings: verifyResp.Warnings,
+ Auth: auth,
}
for _, teamName := range verifyResp.TeamNames {
@@ -110,14 +104,11 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f
}
token := tokenRaw.(string)
- var verifyResp *verifyCredentialsResp
- if verifyResponse, resp, err := b.verifyCredentials(ctx, req, token); err != nil {
+ verifyResp, err := b.verifyCredentials(ctx, req, token)
+ if err != nil {
return nil, err
- } else if resp != nil {
- return resp, nil
- } else {
- verifyResp = verifyResponse
}
+
if !policyutil.EquivalentPolicies(verifyResp.Policies, req.Auth.TokenPolicies) {
return nil, fmt.Errorf("policies do not match")
}
@@ -126,6 +117,7 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f
resp.Auth.Period = verifyResp.Config.TokenPeriod
resp.Auth.TTL = verifyResp.Config.TokenTTL
resp.Auth.MaxTTL = verifyResp.Config.TokenMaxTTL
+ resp.Warnings = verifyResp.Warnings
// Remove old aliases
resp.Auth.GroupAliases = nil
@@ -139,48 +131,64 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f
return resp, nil
}
-func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, token string) (*verifyCredentialsResp, *logical.Response, error) {
+func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, token string) (*verifyCredentialsResp, error) {
+ var warnings []string
config, err := b.Config(ctx, req.Storage)
if err != nil {
- return nil, nil, err
+ return nil, err
}
if config == nil {
- return nil, logical.ErrorResponse("configuration has not been set"), nil
+ return nil, errors.New("configuration has not been set")
}
// Check for a CIDR match.
if len(config.TokenBoundCIDRs) > 0 {
if req.Connection == nil {
- b.Logger().Warn("token bound CIDRs found but no connection information available for validation")
- return nil, nil, logical.ErrPermissionDenied
+ b.Logger().Error("token bound CIDRs found but no connection information available for validation")
+ return nil, logical.ErrPermissionDenied
}
if !cidrutil.RemoteAddrIsOk(req.Connection.RemoteAddr, config.TokenBoundCIDRs) {
- return nil, nil, logical.ErrPermissionDenied
+ return nil, logical.ErrPermissionDenied
}
}
- if config.Organization == "" {
- return nil, logical.ErrorResponse(
- "organization not found in configuration"), nil
- }
-
client, err := b.Client(token)
if err != nil {
- return nil, nil, err
+ return nil, err
}
if config.BaseURL != "" {
parsedURL, err := url.Parse(config.BaseURL)
if err != nil {
- return nil, nil, fmt.Errorf("successfully parsed base_url when set but failing to parse now: %w", err)
+ return nil, fmt.Errorf("successfully parsed base_url when set but failing to parse now: %w", err)
}
client.BaseURL = parsedURL
}
+ if config.OrganizationID == 0 {
+ // Previously we did not verify using the Org ID. So if the Org ID is
+ // not set, we will trust-on-first-use and set it now.
+ err = config.setOrganizationID(ctx, client)
+ if err != nil {
+ b.Logger().Error("failed to set the organization_id on login", "error", err)
+ return nil, err
+ }
+ entry, err := logical.StorageEntryJSON("config", config)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := req.Storage.Put(ctx, entry); err != nil {
+ return nil, err
+ }
+
+ b.Logger().Info("set ID on a trust-on-first-use basis", "organization_id", config.OrganizationID)
+ }
+
// Get the user
user, _, err := client.Users.Get(ctx, "")
if err != nil {
- return nil, nil, err
+ return nil, err
}
// Verify that the user is part of the organization
@@ -194,7 +202,7 @@ func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, t
for {
orgs, resp, err := client.Organizations.List(ctx, "", orgOpt)
if err != nil {
- return nil, nil, err
+ return nil, err
}
allOrgs = append(allOrgs, orgs...)
if resp.NextPage == 0 {
@@ -203,14 +211,27 @@ func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, t
orgOpt.Page = resp.NextPage
}
+ orgLoginName := ""
for _, o := range allOrgs {
- if strings.EqualFold(*o.Login, config.Organization) {
+ if o.GetID() == config.OrganizationID {
org = o
+ orgLoginName = *o.Login
break
}
}
if org == nil {
- return nil, logical.ErrorResponse("user is not part of required org"), nil
+ return nil, errors.New("user is not part of required org")
+ }
+
+ if orgLoginName != config.Organization {
+ warningMsg := fmt.Sprintf(
+ "the organization name has changed to %q. It is recommended to verify and update the organization name in the config: %s=%d",
+ orgLoginName,
+ "organization_id",
+ config.OrganizationID,
+ )
+ b.Logger().Warn(warningMsg)
+ warnings = append(warnings, warningMsg)
}
// Get the teams that this user is part of to determine the policies
@@ -224,7 +245,7 @@ func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, t
for {
teams, resp, err := client.Teams.ListUserTeams(ctx, teamOpt)
if err != nil {
- return nil, nil, err
+ return nil, err
}
allTeams = append(allTeams, teams...)
if resp.NextPage == 0 {
@@ -248,21 +269,24 @@ func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, t
groupPoliciesList, err := b.TeamMap.Policies(ctx, req.Storage, teamNames...)
if err != nil {
- return nil, nil, err
+ return nil, err
}
userPoliciesList, err := b.UserMap.Policies(ctx, req.Storage, []string{*user.Login}...)
if err != nil {
- return nil, nil, err
+ return nil, err
}
- return &verifyCredentialsResp{
+ verifyResp := &verifyCredentialsResp{
User: user,
Org: org,
Policies: append(groupPoliciesList, userPoliciesList...),
TeamNames: teamNames,
Config: config,
- }, nil, nil
+ Warnings: warnings,
+ }
+
+ return verifyResp, nil
}
type verifyCredentialsResp struct {
@@ -271,6 +295,9 @@ type verifyCredentialsResp struct {
Policies []string
TeamNames []string
+ // Warnings to send back to the caller
+ Warnings []string
+
// This is just a cache to send back to the caller
Config *config
}
diff --git a/builtin/credential/github/path_login_test.go b/builtin/credential/github/path_login_test.go
new file mode 100644
index 000000000000..25baf7f811e8
--- /dev/null
+++ b/builtin/credential/github/path_login_test.go
@@ -0,0 +1,186 @@
+package github
+
+import (
+ "context"
+ "errors"
+ "testing"
+
+ "github.com/hashicorp/vault/helper/namespace"
+ "github.com/hashicorp/vault/sdk/logical"
+ "github.com/stretchr/testify/assert"
+)
+
+// TestGitHub_Login tests that we can successfully login with the given config
+func TestGitHub_Login(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+
+ // use a test server to return our mock GH org info
+ ts := setupTestServer(t)
+ defer ts.Close()
+
+ // Write the config
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.UpdateOperation,
+ Data: map[string]interface{}{
+ "organization": "foo-org",
+ "base_url": ts.URL, // base_url will call the test server
+ },
+ Storage: s,
+ })
+ assert.NoError(t, err)
+ assert.NoError(t, resp.Error())
+
+ // Read the config
+ resp, err = b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.ReadOperation,
+ Storage: s,
+ })
+ assert.NoError(t, err)
+ assert.NoError(t, resp.Error())
+
+ // attempt a login
+ resp, err = b.HandleRequest(context.Background(), &logical.Request{
+ Path: "login",
+ Operation: logical.UpdateOperation,
+ Storage: s,
+ })
+
+ expectedMetaData := map[string]string{
+ "org": "foo-org",
+ "username": "user-foo",
+ }
+ assert.Equal(t, expectedMetaData, resp.Auth.Metadata)
+ assert.NoError(t, err)
+ assert.NoError(t, resp.Error())
+}
+
+// TestGitHub_Login_OrgInvalid tests that we cannot login with an ID other than
+// what is set in the config
+func TestGitHub_Login_OrgInvalid(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+ ctx := namespace.RootContext(nil)
+
+ // use a test server to return our mock GH org info
+ ts := setupTestServer(t)
+ defer ts.Close()
+
+ // write and store config
+ config := config{
+ Organization: "foo-org",
+ OrganizationID: 9999,
+ BaseURL: ts.URL + "/", // base_url will call the test server
+ }
+ entry, err := logical.StorageEntryJSON("config", config)
+ if err != nil {
+ t.Fatalf("failed creating storage entry")
+ }
+ if err := s.Put(ctx, entry); err != nil {
+ t.Fatalf("writing to in mem storage failed")
+ }
+
+ // attempt a login
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "login",
+ Operation: logical.UpdateOperation,
+ Storage: s,
+ })
+
+ assert.Nil(t, resp)
+ assert.Error(t, err)
+ assert.Equal(t, errors.New("user is not part of required org"), err)
+}
+
+// TestGitHub_Login_OrgNameChanged tests that we can successfully login with the
+// given config and emit a warning when the organization name has changed
+func TestGitHub_Login_OrgNameChanged(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+ ctx := namespace.RootContext(nil)
+
+ // use a test server to return our mock GH org info
+ ts := setupTestServer(t)
+ defer ts.Close()
+
+ // write and store config
+ // the name does not match what the API will return but the ID does
+ config := config{
+ Organization: "old-name",
+ OrganizationID: 12345,
+ BaseURL: ts.URL + "/", // base_url will call the test server
+ }
+ entry, err := logical.StorageEntryJSON("config", config)
+ if err != nil {
+ t.Fatalf("failed creating storage entry")
+ }
+ if err := s.Put(ctx, entry); err != nil {
+ t.Fatalf("writing to in mem storage failed")
+ }
+
+ // attempt a login
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "login",
+ Operation: logical.UpdateOperation,
+ Storage: s,
+ })
+
+ assert.NoError(t, err)
+ assert.Nil(t, resp.Error())
+ assert.Equal(
+ t,
+ []string{"the organization name has changed to \"foo-org\". It is recommended to verify and update the organization name in the config: organization_id=12345"},
+ resp.Warnings,
+ )
+}
+
+// TestGitHub_Login_NoOrgID tests that we can successfully login with the given
+// config when no organization ID is present and write the fetched ID to the
+// config
+func TestGitHub_Login_NoOrgID(t *testing.T) {
+ b, s := createBackendWithStorage(t)
+ ctx := namespace.RootContext(nil)
+
+ // use a test server to return our mock GH org info
+ ts := setupTestServer(t)
+ defer ts.Close()
+
+ // write and store config without Org ID
+ config := config{
+ Organization: "foo-org",
+ BaseURL: ts.URL + "/", // base_url will call the test server
+ }
+ entry, err := logical.StorageEntryJSON("config", config)
+ if err != nil {
+ t.Fatalf("failed creating storage entry")
+ }
+ if err := s.Put(ctx, entry); err != nil {
+ t.Fatalf("writing to in mem storage failed")
+ }
+
+ // attempt a login
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Path: "login",
+ Operation: logical.UpdateOperation,
+ Storage: s,
+ })
+
+ expectedMetaData := map[string]string{
+ "org": "foo-org",
+ "username": "user-foo",
+ }
+ assert.Equal(t, expectedMetaData, resp.Auth.Metadata)
+ assert.NoError(t, err)
+ assert.NoError(t, resp.Error())
+
+ // Read the config
+ resp, err = b.HandleRequest(context.Background(), &logical.Request{
+ Path: "config",
+ Operation: logical.ReadOperation,
+ Storage: s,
+ })
+ assert.NoError(t, err)
+ assert.NoError(t, resp.Error())
+
+ // the ID should be set, we grab it from the GET /orgs API
+ assert.Equal(t, int64(12345), resp.Data["organization_id"])
+}
diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go
index 17dd6c11b2d1..995bea5982d4 100644
--- a/builtin/logical/pki/backend_test.go
+++ b/builtin/logical/pki/backend_test.go
@@ -1183,21 +1183,21 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep {
}
getRandCsr := func(keyType string, errorOk bool, csrTemplate *x509.CertificateRequest) csrPlan {
- rsaKeyBits := []int{2048, 4096}
+ rsaKeyBits := []int{2048, 3072, 4096}
ecKeyBits := []int{224, 256, 384, 521}
plan := csrPlan{errorOk: errorOk}
var testBitSize int
switch keyType {
case "rsa":
- plan.roleKeyBits = rsaKeyBits[mathRand.Int()%2]
+ plan.roleKeyBits = rsaKeyBits[mathRand.Int()%len(rsaKeyBits)]
testBitSize = plan.roleKeyBits
// If we don't expect an error already, randomly choose a
// key size and expect an error if it's less than the role
// setting
if !keybitSizeRandOff && !errorOk {
- testBitSize = rsaKeyBits[mathRand.Int()%2]
+ testBitSize = rsaKeyBits[mathRand.Int()%len(rsaKeyBits)]
}
if testBitSize < plan.roleKeyBits {
@@ -1205,14 +1205,14 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep {
}
case "ec":
- plan.roleKeyBits = ecKeyBits[mathRand.Int()%4]
+ plan.roleKeyBits = ecKeyBits[mathRand.Int()%len(ecKeyBits)]
testBitSize = plan.roleKeyBits
// If we don't expect an error already, randomly choose a
// key size and expect an error if it's less than the role
// setting
if !keybitSizeRandOff && !errorOk {
- testBitSize = ecKeyBits[mathRand.Int()%4]
+ testBitSize = ecKeyBits[mathRand.Int()%len(ecKeyBits)]
}
if testBitSize < plan.roleKeyBits {
diff --git a/builtin/logical/pki/ca_util.go b/builtin/logical/pki/ca_util.go
index e5009386f539..1e3da0333960 100644
--- a/builtin/logical/pki/ca_util.go
+++ b/builtin/logical/pki/ca_util.go
@@ -50,12 +50,8 @@ func (b *backend) getGenerationParams(
PostalCode: data.Get("postal_code").([]string),
}
- if role.KeyType == "rsa" && role.KeyBits < 2048 {
- errorResp = logical.ErrorResponse("RSA keys < 2048 bits are unsafe and not supported")
- return
- }
-
- if err := certutil.ValidateKeyTypeSignatureLength(role.KeyType, role.KeyBits, &role.SignatureBits); err != nil {
+ var err error
+ if role.KeyBits, role.SignatureBits, err = certutil.ValidateDefaultOrValueKeyTypeSignatureLength(role.KeyType, role.KeyBits, role.SignatureBits); err != nil {
errorResp = logical.ErrorResponse(err.Error())
}
diff --git a/builtin/logical/pki/fields.go b/builtin/logical/pki/fields.go
index fcb01d07b446..67d705a505f7 100644
--- a/builtin/logical/pki/fields.go
+++ b/builtin/logical/pki/fields.go
@@ -250,12 +250,13 @@ the private key!`,
fields["key_bits"] = &framework.FieldSchema{
Type: framework.TypeInt,
- Default: 2048,
- Description: `The number of bits to use. You will almost
-certainly want to change this if you adjust
-the key_type.`,
+ Default: 0,
+ Description: `The number of bits to use. Allowed values are
+0 (universal default); with rsa key_type: 2048 (default), 3072, or
+4096; with ec key_type: 224, 256 (default), 384, or 521; ignored with
+ed25519.`,
DisplayAttrs: &framework.DisplayAttributes{
- Value: 2048,
+ Value: 0,
},
}
diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go
index aa77dcf570fe..444e8071fdba 100644
--- a/builtin/logical/pki/path_roles.go
+++ b/builtin/logical/pki/path_roles.go
@@ -199,10 +199,11 @@ protection use. Defaults to false.`,
"key_bits": {
Type: framework.TypeInt,
- Default: 2048,
- Description: `The number of bits to use. You will almost
-certainly want to change this if you adjust
-the key_type.`,
+ Default: 0,
+ Description: `The number of bits to use. Allowed values are
+0 (universal default); with rsa key_type: 2048 (default), 3072, or
+4096; with ec key_type: 224, 256 (default), 384, or 521; ignored with
+ed25519.`,
},
"signature_bits": &framework.FieldSchema{
@@ -615,17 +616,13 @@ func (b *backend) pathRoleCreate(ctx context.Context, req *logical.Request, data
*entry.GenerateLease = data.Get("generate_lease").(bool)
}
- if entry.KeyType == "rsa" && entry.KeyBits < 2048 {
- return logical.ErrorResponse("RSA keys < 2048 bits are unsafe and not supported"), nil
- }
-
if entry.MaxTTL > 0 && entry.TTL > entry.MaxTTL {
return logical.ErrorResponse(
`"ttl" value must be less than "max_ttl" value`,
), nil
}
- if err := certutil.ValidateKeyTypeSignatureLength(entry.KeyType, entry.KeyBits, &entry.SignatureBits); err != nil {
+ if entry.KeyBits, entry.SignatureBits, err = certutil.ValidateDefaultOrValueKeyTypeSignatureLength(entry.KeyType, entry.KeyBits, entry.SignatureBits); err != nil {
return logical.ErrorResponse(err.Error()), nil
}
diff --git a/builtin/logical/transit/backend_test.go b/builtin/logical/transit/backend_test.go
index bb68d9f02d5f..355b0738c1dd 100644
--- a/builtin/logical/transit/backend_test.go
+++ b/builtin/logical/transit/backend_test.go
@@ -989,6 +989,7 @@ func testConvergentEncryptionCommon(t *testing.T, ver int, keyType keysutil.KeyT
Data: map[string]interface{}{
"derived": false,
"convergent_encryption": true,
+ "type": keyType.String(),
},
}
resp, err := b.HandleRequest(context.Background(), req)
@@ -1009,6 +1010,7 @@ func testConvergentEncryptionCommon(t *testing.T, ver int, keyType keysutil.KeyT
Data: map[string]interface{}{
"derived": true,
"convergent_encryption": true,
+ "type": keyType.String(),
},
}
resp, err = b.HandleRequest(context.Background(), req)
diff --git a/builtin/logical/transit/path_datakey.go b/builtin/logical/transit/path_datakey.go
index 9e9ef2c17340..a9c1f426d928 100644
--- a/builtin/logical/transit/path_datakey.go
+++ b/builtin/logical/transit/path_datakey.go
@@ -5,7 +5,7 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
-
+ "github.com/hashicorp/vault/helper/constants"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/errutil"
"github.com/hashicorp/vault/sdk/helper/keysutil"
@@ -159,6 +159,10 @@ func (b *backend) pathDatakeyWrite(ctx context.Context, req *logical.Request, d
},
}
+ if constants.IsFIPS() && shouldWarnAboutNonceUsage(p, nonce) {
+ resp.AddWarning("A provided nonce value was used within FIPS mode, this violates FIPS 140 compliance.")
+ }
+
if plaintextAllowed {
resp.Data["plaintext"] = base64.StdEncoding.EncodeToString(newKey)
}
diff --git a/builtin/logical/transit/path_encrypt.go b/builtin/logical/transit/path_encrypt.go
index deb564b12926..ac683dadd17e 100644
--- a/builtin/logical/transit/path_encrypt.go
+++ b/builtin/logical/transit/path_encrypt.go
@@ -5,6 +5,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
+ "github.com/hashicorp/vault/helper/constants"
"net/http"
"reflect"
@@ -357,11 +358,16 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d
// Process batch request items. If encryption of any request
// item fails, respectively mark the error in the response
// collection and continue to process other items.
+ warnAboutNonceUsage := false
for i, item := range batchInputItems {
if batchResponseItems[i].Error != "" {
continue
}
+ if !warnAboutNonceUsage && shouldWarnAboutNonceUsage(p, item.DecodedNonce) {
+ warnAboutNonceUsage = true
+ }
+
ciphertext, err := p.Encrypt(item.KeyVersion, item.DecodedContext, item.DecodedNonce, item.Plaintext)
if err != nil {
switch err.(type) {
@@ -411,6 +417,10 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d
}
}
+ if constants.IsFIPS() && warnAboutNonceUsage {
+ resp.AddWarning("A provided nonce value was used within FIPS mode, this violates FIPS 140 compliance.")
+ }
+
if req.Operation == logical.CreateOperation && !upserted {
resp.AddWarning("Attempted creation of the key during the encrypt operation, but it was created beforehand")
}
@@ -431,6 +441,34 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d
return resp, nil
}
+// shouldWarnAboutNonceUsage attempts to determine if we will use a provided nonce or not. Ideally this
+// would be information returned through p.Encrypt but that would require an SDK api change and this is
+// transit specific
+func shouldWarnAboutNonceUsage(p *keysutil.Policy, userSuppliedNonce []byte) bool {
+ if len(userSuppliedNonce) == 0 {
+ return false
+ }
+
+ var supportedKeyType bool
+ switch p.Type {
+ case keysutil.KeyType_AES128_GCM96, keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305:
+ supportedKeyType = true
+ default:
+ supportedKeyType = false
+ }
+
+ if supportedKeyType && p.ConvergentEncryption && p.ConvergentVersion == 1 {
+ // We only use the user supplied nonce for v1 convergent encryption keys
+ return true
+ }
+
+ if supportedKeyType && !p.ConvergentEncryption {
+ return true
+ }
+
+ return false
+}
+
const pathEncryptHelpSyn = `Encrypt a plaintext value or a batch of plaintext
blocks using a named key`
diff --git a/builtin/logical/transit/path_encrypt_test.go b/builtin/logical/transit/path_encrypt_test.go
index 1842e069a513..227ff4cf49ca 100644
--- a/builtin/logical/transit/path_encrypt_test.go
+++ b/builtin/logical/transit/path_encrypt_test.go
@@ -3,6 +3,7 @@ package transit
import (
"context"
"encoding/json"
+ "github.com/hashicorp/vault/sdk/helper/keysutil"
"reflect"
"strings"
"testing"
@@ -729,3 +730,82 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) {
})
}
}
+
+func TestShouldWarnAboutNonceUsage(t *testing.T) {
+ tests := []struct {
+ name string
+ keyTypes []keysutil.KeyType
+ nonce []byte
+ convergentEncryption bool
+ convergentVersion int
+ expected bool
+ }{
+ {
+ name: "-NoConvergent-WithNonce",
+ keyTypes: []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
+ nonce: []byte("testnonce"),
+ convergentEncryption: false,
+ convergentVersion: -1,
+ expected: true,
+ },
+ {
+ name: "-NoConvergent-NoNonce",
+ keyTypes: []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
+ nonce: []byte{},
+ convergentEncryption: false,
+ convergentVersion: -1,
+ expected: false,
+ },
+ {
+ name: "-Convergentv1-WithNonce",
+ keyTypes: []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
+ nonce: []byte("testnonce"),
+ convergentEncryption: true,
+ convergentVersion: 1,
+ expected: true,
+ },
+ {
+ name: "-Convergentv2-WithNonce",
+ keyTypes: []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
+ nonce: []byte("testnonce"),
+ convergentEncryption: true,
+ convergentVersion: 2,
+ expected: false,
+ },
+ {
+ name: "-Convergentv3-WithNonce",
+ keyTypes: []keysutil.KeyType{keysutil.KeyType_AES256_GCM96, keysutil.KeyType_AES128_GCM96, keysutil.KeyType_ChaCha20_Poly1305},
+ nonce: []byte("testnonce"),
+ convergentEncryption: true,
+ convergentVersion: 3,
+ expected: false,
+ },
+ {
+ name: "-NoConvergent-WithNonce",
+ keyTypes: []keysutil.KeyType{keysutil.KeyType_RSA2048, keysutil.KeyType_RSA4096},
+ nonce: []byte("testnonce"),
+ convergentEncryption: false,
+ convergentVersion: -1,
+ expected: false,
+ },
+ }
+
+ for _, tt := range tests {
+ for _, keyType := range tt.keyTypes {
+ testName := keyType.String() + tt.name
+ t.Run(testName, func(t *testing.T) {
+ p := keysutil.Policy{
+ ConvergentEncryption: tt.convergentEncryption,
+ ConvergentVersion: tt.convergentVersion,
+ Type: keyType,
+ }
+
+ actual := shouldWarnAboutNonceUsage(&p, tt.nonce)
+
+ if actual != tt.expected {
+ t.Errorf("Expected actual '%v' but got '%v'", tt.expected, actual)
+ }
+ })
+ }
+ }
+}
diff --git a/builtin/logical/transit/path_hash.go b/builtin/logical/transit/path_hash.go
index f26435d88ee9..5e4c750530db 100644
--- a/builtin/logical/transit/path_hash.go
+++ b/builtin/logical/transit/path_hash.go
@@ -9,6 +9,8 @@ import (
"fmt"
"hash"
+ "golang.org/x/crypto/sha3"
+
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
@@ -31,6 +33,10 @@ func (b *backend) pathHash() *framework.Path {
* sha2-256
* sha2-384
* sha2-512
+* sha3-224
+* sha3-256
+* sha3-384
+* sha3-512
Defaults to "sha2-256".`,
},
@@ -86,6 +92,14 @@ func (b *backend) pathHashWrite(ctx context.Context, req *logical.Request, d *fr
hf = sha512.New384()
case "sha2-512":
hf = sha512.New()
+ case "sha3-224":
+ hf = sha3.New224()
+ case "sha3-256":
+ hf = sha3.New256()
+ case "sha3-384":
+ hf = sha3.New384()
+ case "sha3-512":
+ hf = sha3.New512()
default:
return logical.ErrorResponse(fmt.Sprintf("unsupported algorithm %s", algorithm)), nil
}
diff --git a/builtin/logical/transit/path_hash_test.go b/builtin/logical/transit/path_hash_test.go
index a500bb2a42e4..98ce87889a72 100644
--- a/builtin/logical/transit/path_hash_test.go
+++ b/builtin/logical/transit/path_hash_test.go
@@ -67,6 +67,24 @@ func TestTransit_Hash(t *testing.T) {
req.Data["format"] = "base64"
doRequest(req, false, "2dOA8puXrWodkumH2D+loCZTMB4QBt0rzVGvpZqRR+nK7a+JUhq8DwtoKtzUf7USuDQ8g0oy8yb+m+8AVCzohw==")
+ // Test SHA3
+ req.Data["format"] = "hex"
+ req.Data["algorithm"] = "sha3-224"
+ doRequest(req, false, "ced91e69d89c837e87cff960bd64fd9b9f92325fb9add8988d33d007")
+
+ req.Data["algorithm"] = "sha3-256"
+ doRequest(req, false, "e4bd866ec3fa52df3b7842aa97b448bc859a7606cefcdad1715847f4b82a6c93")
+
+ req.Data["algorithm"] = "sha3-384"
+ doRequest(req, false, "715cd38cbf8d0bab426b6a084d649760be555dd64b34de6db148a3fbf2cd2aa5d8b03eb6eda73a3e9a8769c00b4c2113")
+
+ req.Data["algorithm"] = "sha3-512"
+ doRequest(req, false, "f7cac5ad830422a5408b36a60a60620687be180765a3e2895bc3bdbd857c9e08246c83064d4e3612f0cb927f3ead208413ab98624bf7b0617af0f03f62080976")
+
+ // Test returning SHA3 as base64
+ req.Data["format"] = "base64"
+ doRequest(req, false, "98rFrYMEIqVAizamCmBiBoe+GAdlo+KJW8O9vYV8nggkbIMGTU42EvDLkn8+rSCEE6uYYkv3sGF68PA/YggJdg==")
+
// Test bad input/format/algorithm
req.Data["format"] = "base92"
doRequest(req, true, "")
diff --git a/builtin/logical/transit/path_hmac.go b/builtin/logical/transit/path_hmac.go
index 30a79a40789a..f61017919c9d 100644
--- a/builtin/logical/transit/path_hmac.go
+++ b/builtin/logical/transit/path_hmac.go
@@ -60,6 +60,10 @@ func (b *backend) pathHMAC() *framework.Path {
* sha2-256
* sha2-384
* sha2-512
+* sha3-224
+* sha3-256
+* sha3-384
+* sha3-512
Defaults to "sha2-256".`,
},
diff --git a/builtin/logical/transit/path_hmac_test.go b/builtin/logical/transit/path_hmac_test.go
index 756dc77e559f..108d6218bfd7 100644
--- a/builtin/logical/transit/path_hmac_test.go
+++ b/builtin/logical/transit/path_hmac_test.go
@@ -114,6 +114,24 @@ func TestTransit_HMAC(t *testing.T) {
req.Data["format"] = "base64"
doRequest(req, false, "vault:v1:PSXLXvkvKF4CpU65e2bK1tGBZQpcpCEM32fq2iUoiTyQQCfBcGJJItQ+60tMwWXAPQrC290AzTrNJucGrr4GFA==")
+ // Test SHA3
+ req.Path = "hmac/foo"
+ req.Data["algorithm"] = "sha3-224"
+ doRequest(req, false, "vault:v1:TGipmKH8LR/BkMolYpDYy0BJCIhTtGPDhV2VkQ==")
+
+ req.Data["algorithm"] = "sha3-256"
+ doRequest(req, false, "vault:v1:+px9V/7QYLfdK808zPESC2T/L33uFf4Blzsn9Jy838o=")
+
+ req.Data["algorithm"] = "sha3-384"
+ doRequest(req, false, "vault:v1:YGoRwN4UdTRYZeOER86jsQOB8piWenzLDzJ2wJQK/Jq59rAsY8lh7SCdqqCyFg70")
+
+ req.Data["algorithm"] = "sha3-512"
+ doRequest(req, false, "vault:v1:GrNA8sU88naMPEQ7UZGj9EJl7YJhl03AFHfxcEURFrtvnobdea9ZlZHePpxAx/oCaC7R2HkrAO+Tu3uXPIl3lg==")
+
+ // Test returning SHA3 as base64
+ req.Data["format"] = "base64"
+ doRequest(req, false, "vault:v1:GrNA8sU88naMPEQ7UZGj9EJl7YJhl03AFHfxcEURFrtvnobdea9ZlZHePpxAx/oCaC7R2HkrAO+Tu3uXPIl3lg==")
+
req.Data["algorithm"] = "foobar"
doRequest(req, true, "")
diff --git a/builtin/logical/transit/path_rewrap.go b/builtin/logical/transit/path_rewrap.go
index c32fddc99976..04c38d2f8eb6 100644
--- a/builtin/logical/transit/path_rewrap.go
+++ b/builtin/logical/transit/path_rewrap.go
@@ -4,7 +4,7 @@ import (
"context"
"encoding/base64"
"fmt"
-
+ "github.com/hashicorp/vault/helper/constants"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/errutil"
"github.com/hashicorp/vault/sdk/helper/keysutil"
@@ -128,6 +128,7 @@ func (b *backend) pathRewrapWrite(ctx context.Context, req *logical.Request, d *
p.Lock(false)
}
+ warnAboutNonceUsage := false
for i, item := range batchInputItems {
if batchResponseItems[i].Error != "" {
continue
@@ -145,6 +146,10 @@ func (b *backend) pathRewrapWrite(ctx context.Context, req *logical.Request, d *
}
}
+ if !warnAboutNonceUsage && shouldWarnAboutNonceUsage(p, item.DecodedNonce) {
+ warnAboutNonceUsage = true
+ }
+
ciphertext, err := p.Encrypt(item.KeyVersion, item.DecodedContext, item.DecodedNonce, plaintext)
if err != nil {
switch err.(type) {
@@ -190,6 +195,10 @@ func (b *backend) pathRewrapWrite(ctx context.Context, req *logical.Request, d *
}
}
+ if constants.IsFIPS() && warnAboutNonceUsage {
+ resp.AddWarning("A provided nonce value was used within FIPS mode, this violates FIPS 140 compliance.")
+ }
+
p.Unlock()
return resp, nil
}
diff --git a/builtin/logical/transit/path_sign_verify.go b/builtin/logical/transit/path_sign_verify.go
index 265d63cec198..ade69530df78 100644
--- a/builtin/logical/transit/path_sign_verify.go
+++ b/builtin/logical/transit/path_sign_verify.go
@@ -88,6 +88,10 @@ derivation is enabled; currently only available with ed25519 keys.`,
* sha2-256
* sha2-384
* sha2-512
+* sha3-224
+* sha3-256
+* sha3-384
+* sha3-512
Defaults to "sha2-256". Not valid for all key types,
including ed25519.`,
@@ -183,6 +187,10 @@ derivation is enabled; currently only available with ed25519 keys.`,
* sha2-256
* sha2-384
* sha2-512
+* sha3-224
+* sha3-256
+* sha3-384
+* sha3-512
Defaults to "sha2-256". Not valid for all key types.`,
},
diff --git a/builtin/logical/transit/path_sign_verify_test.go b/builtin/logical/transit/path_sign_verify_test.go
index 40df90838b19..072f8a265fa1 100644
--- a/builtin/logical/transit/path_sign_verify_test.go
+++ b/builtin/logical/transit/path_sign_verify_test.go
@@ -237,6 +237,26 @@ func testTransit_SignVerify_ECDSA(t *testing.T, bits int) {
sig = signRequest(req, false, "")
verifyRequest(req, false, "", sig)
+ req.Data["hash_algorithm"] = "sha2-512"
+ sig = signRequest(req, false, "")
+ verifyRequest(req, false, "", sig)
+
+ req.Data["hash_algorithm"] = "sha3-224"
+ sig = signRequest(req, false, "")
+ verifyRequest(req, false, "", sig)
+
+ req.Data["hash_algorithm"] = "sha3-256"
+ sig = signRequest(req, false, "")
+ verifyRequest(req, false, "", sig)
+
+ req.Data["hash_algorithm"] = "sha3-384"
+ sig = signRequest(req, false, "")
+ verifyRequest(req, false, "", sig)
+
+ req.Data["hash_algorithm"] = "sha3-512"
+ sig = signRequest(req, false, "")
+ verifyRequest(req, false, "", sig)
+
req.Data["prehashed"] = true
sig = signRequest(req, false, "")
verifyRequest(req, false, "", sig)
diff --git a/changelog/12792.txt b/changelog/12792.txt
index 2785d111bd1b..76f5875e73ff 100644
--- a/changelog/12792.txt
+++ b/changelog/12792.txt
@@ -1,3 +1,3 @@
-```release-note: feature
-core: reading `sys/mounts/:path` now returns the configuration for the secret engine at the given path
+```release-note:improvement
+core: Reading `sys/mounts/:path` now returns the configuration for the secret engine at the given path
```
diff --git a/changelog/12795.txt b/changelog/12795.txt
index fb4ebcc5586f..5b360beda625 100644
--- a/changelog/12795.txt
+++ b/changelog/12795.txt
@@ -1,3 +1,3 @@
-```release-note:feature
+```release-note:improvement
core/pki: Support Y10K value in notAfter field to be compliant with IEEE 802.1AR-2018 standard
-```
\ No newline at end of file
+```
diff --git a/changelog/12976.txt b/changelog/12976.txt
new file mode 100644
index 000000000000..1dea358d9db9
--- /dev/null
+++ b/changelog/12976.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Adds flight icons to UI
+```
\ No newline at end of file
diff --git a/changelog/13022.txt b/changelog/13022.txt
index 378b37cbc2b6..bb3d3a69ea07 100644
--- a/changelog/13022.txt
+++ b/changelog/13022.txt
@@ -1,3 +1,3 @@
```release-note:improvement
-implements Login method in Go client libraries for GCP and Azure auth methods
-```
\ No newline at end of file
+api: Implements Login method in Go client libraries for GCP and Azure auth methods
+```
diff --git a/changelog/13024.txt b/changelog/13024.txt
new file mode 100644
index 000000000000..97aea1b90bd3
--- /dev/null
+++ b/changelog/13024.txt
@@ -0,0 +1,3 @@
+```release-note:feature
+**Report in-flight requests**:Adding a trace capability to show in-flight requests, and a new gauge metric to show the total number of in-flight requests
+```
diff --git a/changelog/13080.txt b/changelog/13080.txt
new file mode 100644
index 000000000000..9c3ed52dc68b
--- /dev/null
+++ b/changelog/13080.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+secrets/pki: Default value for key_bits changed to 0, enabling key_type=ec key generation with default value
+```
diff --git a/changelog/13178.txt b/changelog/13178.txt
index 10bb3b890dae..67f6b2a7b5bc 100644
--- a/changelog/13178.txt
+++ b/changelog/13178.txt
@@ -1,3 +1,3 @@
```release-note:improvement
-raft: set InitialMmapSize to 100GB on 64bit architectures
+storage/raft: Set InitialMmapSize to 100GB on 64bit architectures
```
diff --git a/changelog/13202.txt b/changelog/13202.txt
deleted file mode 100644
index 3496665efc9c..000000000000
--- a/changelog/13202.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:feature
-/sys/mounts/:path/tune: Add `allowed_managed_keys` field to mount config which is a list of managed key registry entry names that the mount in question is allowed to access.
-```
\ No newline at end of file
diff --git a/changelog/13324.txt b/changelog/13324.txt
new file mode 100644
index 000000000000..f0bced301614
--- /dev/null
+++ b/changelog/13324.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+core: Replace "master key" terminology with "root key"
+```
diff --git a/changelog/13332.txt b/changelog/13332.txt
new file mode 100644
index 000000000000..968f32ad8633
--- /dev/null
+++ b/changelog/13332.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+auth/github: Use the Organization ID instead of the Organization name to verify the org membership.
+```
diff --git a/changelog/13365.txt b/changelog/13365.txt
new file mode 100644
index 000000000000..65284ab7ba53
--- /dev/null
+++ b/changelog/13365.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+auth/jwt: The Authorization Code flow makes use of the Proof Key for Code Exchange (PKCE) extension.
+```
diff --git a/changelog/13367.txt b/changelog/13367.txt
new file mode 100644
index 000000000000..9c2a5bb9f2c2
--- /dev/null
+++ b/changelog/13367.txt
@@ -0,0 +1,3 @@
+```release-note:feature
+secrets/transit: Add support for SHA-3 in the Transit backend.
+```
diff --git a/changelog/13395.txt b/changelog/13395.txt
new file mode 100644
index 000000000000..d8f2e71a566c
--- /dev/null
+++ b/changelog/13395.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+core/identity: Support updating an alias' `custom_metadata` to be empty.
+```
diff --git a/changelog/13396.txt b/changelog/13396.txt
new file mode 100644
index 000000000000..6600abedf19e
--- /dev/null
+++ b/changelog/13396.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: Fix client count current month data not showing unless monthly history data exists
+```
diff --git a/changelog/13408.txt b/changelog/13408.txt
new file mode 100644
index 000000000000..4861b177763b
--- /dev/null
+++ b/changelog/13408.txt
@@ -0,0 +1,3 @@
+```release-note:change
+go: Update go version to 1.17.5
+```
diff --git a/command/agent.go b/command/agent.go
index 2870227a30d5..5cebb729bd7d 100644
--- a/command/agent.go
+++ b/command/agent.go
@@ -565,7 +565,7 @@ func (c *AgentCommand) Run(args []string) int {
AAD: aad,
})
if err != nil {
- c.UI.Error(fmt.Sprintf("Error opening persistent cache: %v", err))
+ c.UI.Error(fmt.Sprintf("Error opening persistent cache with wrapper: %v", err))
return 1
}
diff --git a/command/commands.go b/command/commands.go
index bf5daa7474d4..a3846cd414cc 100644
--- a/command/commands.go
+++ b/command/commands.go
@@ -116,6 +116,8 @@ const (
flagNameAllowedResponseHeaders = "allowed-response-headers"
// flagNameTokenType is the flag name used to force a specific token type
flagNameTokenType = "token-type"
+ // flagNameAllowedManagedKeys is the flag name used for auth/secrets enable
+ flagNameAllowedManagedKeys = "allowed-managed-keys"
)
var (
diff --git a/command/debug.go b/command/debug.go
index afd4471d0f74..4e6a12a6c3e5 100644
--- a/command/debug.go
+++ b/command/debug.go
@@ -17,6 +17,7 @@ import (
"github.com/hashicorp/go-secure-stdlib/gatedwriter"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/vault/api"
+ "github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/version"
"github.com/mholt/archiver"
@@ -106,6 +107,7 @@ type DebugCommand struct {
metricsCollection []map[string]interface{}
replicationStatusCollection []map[string]interface{}
serverStatusCollection []map[string]interface{}
+ inFlightReqStatusCollection []map[string]interface{}
// cachedClient holds the client retrieved during preflight
cachedClient *api.Client
@@ -480,7 +482,7 @@ func (c *DebugCommand) preflight(rawArgs []string) (string, error) {
}
func (c *DebugCommand) defaultTargets() []string {
- return []string{"config", "host", "metrics", "pprof", "replication-status", "server-status", "log"}
+ return []string{"config", "host", "requests", "metrics", "pprof", "replication-status", "server-status", "log"}
}
func (c *DebugCommand) captureStaticTargets() error {
@@ -492,6 +494,7 @@ func (c *DebugCommand) captureStaticTargets() error {
if err != nil {
c.captureError("config", err)
c.logger.Error("config: error capturing config state", "error", err)
+ return nil
}
if resp != nil && resp.Data != nil {
@@ -580,6 +583,16 @@ func (c *DebugCommand) capturePollingTargets() error {
})
}
+ // Collect in-flight request status if target is specified
+ if strutil.StrListContains(c.flagTargets, "requests") {
+ g.Add(func() error {
+ c.collectInFlightRequestStatus(ctx)
+ return nil
+ }, func(error) {
+ cancelFunc()
+ })
+ }
+
if strutil.StrListContains(c.flagTargets, "log") {
g.Add(func() error {
c.writeLogs(ctx)
@@ -611,7 +624,9 @@ func (c *DebugCommand) capturePollingTargets() error {
if err := c.persistCollection(c.hostInfoCollection, "host_info.json"); err != nil {
c.UI.Error(fmt.Sprintf("Error writing data to %s: %v", "host_info.json", err))
}
-
+ if err := c.persistCollection(c.inFlightReqStatusCollection, "requests.json"); err != nil {
+ c.UI.Error(fmt.Sprintf("Error writing data to %s: %v", "requests.json", err))
+ }
return nil
}
@@ -635,6 +650,7 @@ func (c *DebugCommand) collectHostInfo(ctx context.Context) {
resp, err := c.cachedClient.RawRequestWithContext(ctx, r)
if err != nil {
c.captureError("host", err)
+ return
}
if resp != nil {
defer resp.Body.Close()
@@ -642,6 +658,7 @@ func (c *DebugCommand) collectHostInfo(ctx context.Context) {
secret, err := api.ParseSecret(resp.Body)
if err != nil {
c.captureError("host", err)
+ return
}
if secret != nil && secret.Data != nil {
hostEntry := secret.Data
@@ -829,6 +846,7 @@ func (c *DebugCommand) collectReplicationStatus(ctx context.Context) {
resp, err := c.cachedClient.RawRequestWithContext(ctx, r)
if err != nil {
c.captureError("replication-status", err)
+ return
}
if resp != nil {
defer resp.Body.Close()
@@ -836,6 +854,7 @@ func (c *DebugCommand) collectReplicationStatus(ctx context.Context) {
secret, err := api.ParseSecret(resp.Body)
if err != nil {
c.captureError("replication-status", err)
+ return
}
if secret != nil && secret.Data != nil {
replicationEntry := secret.Data
@@ -880,6 +899,48 @@ func (c *DebugCommand) collectServerStatus(ctx context.Context) {
}
}
+func (c *DebugCommand) collectInFlightRequestStatus(ctx context.Context) {
+
+ idxCount := 0
+ intervalTicker := time.Tick(c.flagInterval)
+
+ for {
+ if idxCount > 0 {
+ select {
+ case <-ctx.Done():
+ return
+ case <-intervalTicker:
+ }
+ }
+
+ c.logger.Info("capturing in-flight request status", "count", idxCount)
+ idxCount++
+
+ req := c.cachedClient.NewRequest("GET", "/v1/sys/in-flight-req")
+ resp, err := c.cachedClient.RawRequestWithContext(ctx, req)
+ if err != nil {
+ c.captureError("requests", err)
+ return
+ }
+
+ var data map[string]interface{}
+ if resp != nil {
+ defer resp.Body.Close()
+ err = jsonutil.DecodeJSONFromReader(resp.Body, &data)
+ if err != nil {
+ c.captureError("requests", err)
+ return
+ }
+
+ statusEntry := map[string]interface{}{
+ "timestamp": time.Now().UTC(),
+ "in_flight_requests": data,
+ }
+ c.inFlightReqStatusCollection = append(c.inFlightReqStatusCollection, statusEntry)
+ }
+ }
+}
+
// persistCollection writes the collected data for a particular target onto the
// specified file. If the collection is empty, it returns immediately.
func (c *DebugCommand) persistCollection(collection []map[string]interface{}, outFile string) error {
diff --git a/command/debug_test.go b/command/debug_test.go
index 885b0de63ef5..7c46eb5bd671 100644
--- a/command/debug_test.go
+++ b/command/debug_test.go
@@ -235,6 +235,11 @@ func TestDebugCommand_CaptureTargets(t *testing.T) {
[]string{"server-status"},
[]string{"server_status.json"},
},
+ {
+ "in-flight-req",
+ []string{"requests"},
+ []string{"requests.json"},
+ },
{
"all-minus-pprof",
[]string{"config", "host", "metrics", "replication-status", "server-status"},
diff --git a/command/operator_init.go b/command/operator_init.go
index 2cdba009a729..a8b8e5601024 100644
--- a/command/operator_init.go
+++ b/command/operator_init.go
@@ -57,10 +57,10 @@ Usage: vault operator init [options]
same storage backend in HA mode, you only need to initialize one Vault to
initialize the storage backend.
- During initialization, Vault generates an in-memory master key and applies
- Shamir's secret sharing algorithm to disassemble that master key into a
+ During initialization, Vault generates an in-memory root key and applies
+ Shamir's secret sharing algorithm to disassemble that root key into a
configuration number of key shares such that a configurable subset of those
- key shares must come together to regenerate the master key. These keys are
+ key shares must come together to regenerate the root key. These keys are
often called "unseal keys" in Vault's documentation.
This command cannot be run against an already-initialized Vault cluster.
@@ -105,7 +105,7 @@ func (c *OperatorInitCommand) Flags() *FlagSets {
Target: &c.flagKeyShares,
Default: defKeyShares,
Completion: complete.PredictAnything,
- Usage: "Number of key shares to split the generated master key into. " +
+ Usage: "Number of key shares to split the generated root key into. " +
"This is the number of \"unseal keys\" to generate.",
})
@@ -115,7 +115,7 @@ func (c *OperatorInitCommand) Flags() *FlagSets {
Target: &c.flagKeyThreshold,
Default: defKeyThreshold,
Completion: complete.PredictAnything,
- Usage: "Number of key shares required to reconstruct the master key. " +
+ Usage: "Number of key shares required to reconstruct the root key. " +
"This must be less than or equal to -key-shares.",
})
@@ -447,8 +447,8 @@ func (c *OperatorInitCommand) init(client *api.Client, req *api.InitRequest) int
c.UI.Output("")
c.UI.Output(wrapAtLength(fmt.Sprintf(
- "Vault does not store the generated master key. Without at least %d "+
- "keys to reconstruct the master key, Vault will remain permanently "+
+ "Vault does not store the generated root key. Without at least %d "+
+ "keys to reconstruct the root key, Vault will remain permanently "+
"sealed!",
req.SecretThreshold)))
diff --git a/command/operator_rekey.go b/command/operator_rekey.go
index ca9a316cb3de..b73349405daa 100644
--- a/command/operator_rekey.go
+++ b/command/operator_rekey.go
@@ -51,7 +51,7 @@ Usage: vault operator rekey [options] [KEY]
Generates a new set of unseal keys. This can optionally change the total
number of key shares or the required threshold of those key shares to
- reconstruct the master key. This operation is zero downtime, but it requires
+ reconstruct the root key. This operation is zero downtime, but it requires
the Vault is unsealed and a quorum of existing unseal keys are provided.
An unseal key may be provided directly on the command line as an argument to
@@ -129,7 +129,7 @@ func (c *OperatorRekeyCommand) Flags() *FlagSets {
Target: &c.flagKeyShares,
Default: 5,
Completion: complete.PredictAnything,
- Usage: "Number of key shares to split the generated master key into. " +
+ Usage: "Number of key shares to split the generated root key into. " +
"This is the number of \"unseal keys\" to generate.",
})
@@ -139,7 +139,7 @@ func (c *OperatorRekeyCommand) Flags() *FlagSets {
Target: &c.flagKeyThreshold,
Default: 3,
Completion: complete.PredictAnything,
- Usage: "Number of key shares required to reconstruct the master key. " +
+ Usage: "Number of key shares required to reconstruct the root key. " +
"This must be less than or equal to -key-shares.",
})
diff --git a/command/operator_seal.go b/command/operator_seal.go
index 9f2ec6656ed7..369ec3215d66 100644
--- a/command/operator_seal.go
+++ b/command/operator_seal.go
@@ -27,11 +27,11 @@ Usage: vault operator seal [options]
Seals the Vault server. Sealing tells the Vault server to stop responding
to any operations until it is unsealed. When sealed, the Vault server
- discards its in-memory master key to unlock the data, so it is physically
+ discards its in-memory root key to unlock the data, so it is physically
blocked from responding to operations unsealed.
If an unseal is in progress, sealing the Vault will reset the unsealing
- process. Users will have to re-enter their portions of the master key again.
+ process. Users will have to re-enter their portions of the root key again.
This command does nothing if the Vault server is already sealed.
diff --git a/command/operator_unseal.go b/command/operator_unseal.go
index da8641ba51de..8cdd06d38408 100644
--- a/command/operator_unseal.go
+++ b/command/operator_unseal.go
@@ -34,9 +34,9 @@ func (c *OperatorUnsealCommand) Help() string {
helpText := `
Usage: vault operator unseal [options] [KEY]
- Provide a portion of the master key to unseal a Vault server. Vault starts
+ Provide a portion of the root key to unseal a Vault server. Vault starts
in a sealed state. It cannot perform operations until it is unsealed. This
- command accepts a portion of the master key (an "unseal key").
+ command accepts a portion of the root key (an "unseal key").
The unseal key can be supplied as an argument to the command, but this is
not recommended as the unseal key will be available in your history:
diff --git a/command/secrets_enable.go b/command/secrets_enable.go
index cb4671ba3943..72b7b89b5585 100644
--- a/command/secrets_enable.go
+++ b/command/secrets_enable.go
@@ -37,6 +37,7 @@ type SecretsEnableCommand struct {
flagSealWrap bool
flagExternalEntropyAccess bool
flagVersion int
+ flagAllowedManagedKeys []string
}
func (c *SecretsEnableCommand) Synopsis() string {
@@ -209,6 +210,15 @@ func (c *SecretsEnableCommand) Flags() *FlagSets {
Usage: "Select the version of the engine to run. Not supported by all engines.",
})
+ f.StringSliceVar(&StringSliceVar{
+ Name: flagNameAllowedManagedKeys,
+ Target: &c.flagAllowedManagedKeys,
+ Usage: "Managed key name(s) that the mount in question is allowed to access. " +
+ "Note that multiple keys may be specified either by providing the key names " +
+ "as a comma separated string or by providing this option multiple times, " +
+ "each time with 1 key.",
+ })
+
return set
}
@@ -307,6 +317,10 @@ func (c *SecretsEnableCommand) Run(args []string) int {
if fl.Name == flagNameAllowedResponseHeaders {
mountInput.Config.AllowedResponseHeaders = c.flagAllowedResponseHeaders
}
+
+ if fl.Name == flagNameAllowedManagedKeys {
+ mountInput.Config.AllowedManagedKeys = c.flagAllowedManagedKeys
+ }
})
if err := client.Sys().Mount(mountPath, mountInput); err != nil {
diff --git a/command/secrets_enable_test.go b/command/secrets_enable_test.go
index bcc581a4e108..f5a54a8cc8da 100644
--- a/command/secrets_enable_test.go
+++ b/command/secrets_enable_test.go
@@ -113,6 +113,7 @@ func TestSecretsEnableCommand_Run(t *testing.T) {
"-passthrough-request-headers", "authorization,authentication",
"-passthrough-request-headers", "www-authentication",
"-allowed-response-headers", "authorization",
+ "-allowed-managed-keys", "key1,key2",
"-force-no-cache",
"pki",
})
@@ -162,6 +163,9 @@ func TestSecretsEnableCommand_Run(t *testing.T) {
if diff := deep.Equal([]string{"foo,bar"}, mountInfo.Config.AuditNonHMACResponseKeys); len(diff) > 0 {
t.Errorf("Failed to find expected values in AuditNonHMACResponseKeys. Difference is: %v", diff)
}
+ if diff := deep.Equal([]string{"key1,key2"}, mountInfo.Config.AllowedManagedKeys); len(diff) > 0 {
+ t.Errorf("Failed to find expected values in AllowedManagedKeys. Difference is: %v", diff)
+ }
})
diff --git a/command/secrets_tune.go b/command/secrets_tune.go
index a7883a618cd0..3e20367ea6e0 100644
--- a/command/secrets_tune.go
+++ b/command/secrets_tune.go
@@ -30,6 +30,7 @@ type SecretsTuneCommand struct {
flagAllowedResponseHeaders []string
flagOptions map[string]string
flagVersion int
+ flagAllowedManagedKeys []string
}
func (c *SecretsTuneCommand) Synopsis() string {
@@ -137,6 +138,15 @@ func (c *SecretsTuneCommand) Flags() *FlagSets {
Usage: "Select the version of the engine to run. Not supported by all engines.",
})
+ f.StringSliceVar(&StringSliceVar{
+ Name: flagNameAllowedManagedKeys,
+ Target: &c.flagAllowedManagedKeys,
+ Usage: "Managed key name(s) that the mount in question is allowed to access. " +
+ "Note that multiple keys may be specified either by providing the key names " +
+ "as a comma separated string or by providing this option multiple times, " +
+ "each time with 1 key.",
+ })
+
return set
}
@@ -213,6 +223,10 @@ func (c *SecretsTuneCommand) Run(args []string) int {
if fl.Name == flagNameAllowedResponseHeaders {
mountConfigInput.AllowedResponseHeaders = c.flagAllowedResponseHeaders
}
+
+ if fl.Name == flagNameAllowedManagedKeys {
+ mountConfigInput.AllowedManagedKeys = c.flagAllowedManagedKeys
+ }
})
if err := client.Sys().TuneMount(mountPath, mountConfigInput); err != nil {
diff --git a/command/secrets_tune_test.go b/command/secrets_tune_test.go
index de732873790e..f51b8fb34b78 100644
--- a/command/secrets_tune_test.go
+++ b/command/secrets_tune_test.go
@@ -170,6 +170,7 @@ func TestSecretsTuneCommand_Run(t *testing.T) {
"-passthrough-request-headers", "authorization",
"-passthrough-request-headers", "www-authentication",
"-allowed-response-headers", "authorization,www-authentication",
+ "-allowed-managed-keys", "key1,key2",
"-listing-visibility", "unauth",
"mount_tune_integration/",
})
@@ -216,6 +217,9 @@ func TestSecretsTuneCommand_Run(t *testing.T) {
if diff := deep.Equal([]string{"foo,bar"}, mountInfo.Config.AuditNonHMACResponseKeys); len(diff) > 0 {
t.Errorf("Failed to find expected values in AuditNonHMACResponseKeys. Difference is: %v", diff)
}
+ if diff := deep.Equal([]string{"key1,key2"}, mountInfo.Config.AllowedManagedKeys); len(diff) > 0 {
+ t.Errorf("Failed to find expected values in AllowedManagedKeys. Difference is: %v", diff)
+ }
})
t.Run("flags_description", func(t *testing.T) {
diff --git a/command/server.go b/command/server.go
index 718009b8cf41..5b8eb634af8e 100644
--- a/command/server.go
+++ b/command/server.go
@@ -1547,6 +1547,9 @@ func (c *ServerCommand) Run(args []string) int {
c.logger.Error(err.Error())
}
+ // Setting log request with the new value in the config after reload
+ core.ReloadLogRequestsLevel()
+
if config.LogLevel != "" {
configLogLevel := strings.ToLower(strings.TrimSpace(config.LogLevel))
switch configLogLevel {
diff --git a/command/server/config.go b/command/server/config.go
index c478906a7928..e79cce6e9cdb 100644
--- a/command/server/config.go
+++ b/command/server/config.go
@@ -8,10 +8,13 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "regexp"
"strconv"
"strings"
"time"
+ wrapping "github.com/hashicorp/go-kms-wrapping"
+
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/hcl"
@@ -23,6 +26,8 @@ var entConfigValidate = func(_ *Config, _ string) []configutil.ConfigError {
return nil
}
+var kmsLibraryValidator = defaultKmsLibraryValidator
+
// Config is the configuration for the vault server.
type Config struct {
UnusedKeys configutil.UnusedKeyMap `hcl:",unusedKeyPositions"`
@@ -77,11 +82,16 @@ type Config struct {
EnableResponseHeaderHostname bool `hcl:"-"`
EnableResponseHeaderHostnameRaw interface{} `hcl:"enable_response_header_hostname"`
+ LogRequestsLevel string `hcl:"-"`
+ LogRequestsLevelRaw interface{} `hcl:"log_requests_level"`
+
EnableResponseHeaderRaftNodeID bool `hcl:"-"`
EnableResponseHeaderRaftNodeIDRaw interface{} `hcl:"enable_response_header_raft_node_id"`
License string `hcl:"-"`
LicensePath string `hcl:"license_path"`
+
+ KmsLibraries map[string]*KMSLibrary `hcl:"-"`
}
const (
@@ -99,6 +109,9 @@ func (c *Config) Validate(sourceFilePath string) []configutil.ConfigError {
for _, l := range c.Listeners {
results = append(results, l.Validate(sourceFilePath)...)
}
+ for _, kmslibrary := range c.KmsLibraries {
+ results = append(results, kmslibrary.Validate(sourceFilePath)...)
+ }
results = append(results, c.validateEnt(sourceFilePath)...)
return results
}
@@ -168,6 +181,24 @@ func (b *ServiceRegistration) GoString() string {
return fmt.Sprintf("*%#v", *b)
}
+// KMSLibrary is a per-server configuration that will be further augmented with managed key configuration to
+// build up a KMS wrapper type to delegate encryption operations to HSMs
+type KMSLibrary struct {
+ UnusedKeys configutil.UnusedKeyMap `hcl:",unusedKeyPositions"`
+ FoundKeys []string `hcl:",decodedFields"`
+ Type string `hcl:"-"`
+ Name string `hcl:"name"`
+ Library string `hcl:"library"`
+}
+
+func (k *KMSLibrary) Validate(source string) []configutil.ConfigError {
+ return configutil.ValidateUnusedFields(k.UnusedKeys, source)
+}
+
+func (k *KMSLibrary) GoString() string {
+ return fmt.Sprintf("*%#v", *k)
+}
+
func NewConfig() *Config {
return &Config{
SharedConfig: new(configutil.SharedConfig),
@@ -292,6 +323,11 @@ func (c *Config) Merge(c2 *Config) *Config {
result.EnableResponseHeaderHostname = c2.EnableResponseHeaderHostname
}
+ result.LogRequestsLevel = c.LogRequestsLevel
+ if c2.LogRequestsLevel != "" {
+ result.LogRequestsLevel = c2.LogRequestsLevel
+ }
+
result.EnableResponseHeaderRaftNodeID = c.EnableResponseHeaderRaftNodeID
if c2.EnableResponseHeaderRaftNodeID {
result.EnableResponseHeaderRaftNodeID = c2.EnableResponseHeaderRaftNodeID
@@ -480,6 +516,11 @@ func ParseConfig(d, source string) (*Config, error) {
}
}
+ if result.LogRequestsLevelRaw != nil {
+ result.LogRequestsLevel = strings.ToLower(strings.TrimSpace(result.LogRequestsLevelRaw.(string)))
+ result.LogRequestsLevelRaw = ""
+ }
+
if result.EnableResponseHeaderRaftNodeIDRaw != nil {
if result.EnableResponseHeaderRaftNodeID, err = parseutil.ParseBool(result.EnableResponseHeaderRaftNodeIDRaw); err != nil {
return nil, err
@@ -528,6 +569,14 @@ func ParseConfig(d, source string) (*Config, error) {
}
}
+ // Parse KMSLibraries sections if any
+ if o := list.Filter("kms_library"); len(o.Items) > 0 {
+ delete(result.UnusedKeys, "kms_library")
+ if err := parseKmsLibraries(result, o); err != nil {
+ return nil, fmt.Errorf("error parsing 'kms_library': %w", err)
+ }
+ }
+
entConfig := &(result.entConfig)
if err := entConfig.parseConfig(list); err != nil {
return nil, fmt.Errorf("error parsing enterprise config: %w", err)
@@ -794,6 +843,75 @@ func parseServiceRegistration(result *Config, list *ast.ObjectList, name string)
return nil
}
+func parseKmsLibraries(result *Config, list *ast.ObjectList) error {
+ result.KmsLibraries = make(map[string]*KMSLibrary, len(list.Items))
+
+ for _, item := range list.Items {
+ library, err := decodeKmsLibrary(item)
+ if err != nil {
+ return err
+ }
+
+ if err := validateKmsLibrary(library); err != nil {
+ return err
+ }
+
+ if _, ok := result.KmsLibraries[library.Name]; ok {
+ return fmt.Errorf("duplicated kms_library configuration sections with name %s", library.Name)
+ }
+
+ result.KmsLibraries[library.Name] = library
+ }
+ return nil
+}
+
+func decodeKmsLibrary(item *ast.ObjectItem) (*KMSLibrary, error) {
+ library := &KMSLibrary{}
+ if err := hcl.DecodeObject(&library, item.Val); err != nil {
+ return nil, multierror.Prefix(err, "kms_library")
+ }
+
+ if len(item.Keys) != 1 {
+ return nil, errors.New("kms_library section was missing a type")
+ }
+
+ library.Type = strings.ToLower(item.Keys[0].Token.Value().(string))
+ library.Name = strings.ToLower(library.Name)
+
+ return library, nil
+}
+
+func defaultKmsLibraryValidator(kms *KMSLibrary) error {
+ switch kms.Type {
+ case wrapping.PKCS11:
+ return fmt.Errorf("KMS type 'pkcs11' requires the Vault Enterprise HSM binary")
+
+ default:
+ return fmt.Errorf("unknown KMS type %q", kms.Type)
+ }
+}
+
+func validateKmsLibrary(kmsConfig *KMSLibrary) error {
+ if kmsConfig.Library == "" {
+ return fmt.Errorf("library key can not be blank within kms_library type: %s", kmsConfig.Type)
+ }
+
+ if kmsConfig.Name == "" {
+ return fmt.Errorf("name key can not be blank within kms_library type: %s", kmsConfig.Type)
+ }
+
+ nameRegex := regexp.MustCompile("^[\\w._-]+$")
+ if !nameRegex.MatchString(kmsConfig.Name) {
+ return fmt.Errorf("value ('%s') for name field contained invalid characters within kms_library type: %s", kmsConfig.Name, kmsConfig.Type)
+ }
+
+ if err := kmsLibraryValidator(kmsConfig); err != nil {
+ return err
+ }
+
+ return nil
+}
+
// Sanitized returns a copy of the config with all values that are considered
// sensitive stripped. It also strips all `*Raw` values that are mainly
// used for parsing.
@@ -840,6 +958,8 @@ func (c *Config) Sanitized() map[string]interface{} {
"enable_response_header_hostname": c.EnableResponseHeaderHostname,
"enable_response_header_raft_node_id": c.EnableResponseHeaderRaftNodeID,
+
+ "log_requests_level": c.LogRequestsLevel,
}
for k, v := range sharedResult {
result[k] = v
diff --git a/command/server/config_oss_test.go b/command/server/config_oss_test.go
index 6f466ddf6d01..84abc4c8b91f 100644
--- a/command/server/config_oss_test.go
+++ b/command/server/config_oss_test.go
@@ -17,3 +17,7 @@ func TestLoadConfigFile_json2(t *testing.T) {
func TestParseEntropy(t *testing.T) {
testParseEntropy(t, true)
}
+
+func TestKmsLibraryFailsForNonHSMBinary(t *testing.T) {
+ testKmsLibraryFailsForNonHSMBinary(t)
+}
diff --git a/command/server/config_test_helpers.go b/command/server/config_test_helpers.go
index 106ad7dce22b..310e6b3b4720 100644
--- a/command/server/config_test_helpers.go
+++ b/command/server/config_test_helpers.go
@@ -701,6 +701,7 @@ func testConfig_Sanitized(t *testing.T) {
"enable_ui": true,
"enable_response_header_hostname": false,
"enable_response_header_raft_node_id": false,
+ "log_requests_level": "basic",
"ha_storage": map[string]interface{}{
"cluster_addr": "top_level_cluster_addr",
"disable_clustering": true,
@@ -1063,3 +1064,26 @@ func testConfigRaftAutopilot(t *testing.T) {
t.Fatal(diff)
}
}
+
+func testKmsLibraryFailsForNonHSMBinary(t *testing.T) {
+ config := `
+ui = false
+storage "file" {
+ path = "/tmp/test"
+}
+
+listener "tcp" {
+ address = "0.0.0.0:8200"
+ tls_cert_file = "/opt/vault/tls/tls.crt"
+ tls_key_file = "/opt/vault/tls/tls.key"
+}
+
+kms_library "pkcs11" {
+ name="Logical1"
+ library="a library"
+}
+`
+ _, err := ParseConfig(config, "")
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "requires the Vault Enterprise HSM binary")
+}
diff --git a/command/server/listener_test.go b/command/server/listener_test.go
index 5b2271eefc34..cda5b733e26b 100644
--- a/command/server/listener_test.go
+++ b/command/server/listener_test.go
@@ -6,6 +6,7 @@ import (
"io"
"net"
"testing"
+
)
type testListenerConnFn func(net.Listener) (net.Conn, error)
@@ -66,3 +67,15 @@ func testListenerImpl(t *testing.T, ln net.Listener, connFn testListenerConnFn,
t.Fatalf("bad: %v", buf.String())
}
}
+
+
+func TestProfilingUnauthenticatedInFlightAccess(t *testing.T) {
+
+ config, err := LoadConfigFile("./test-fixtures/unauth_in_flight_access.hcl")
+ if err != nil {
+ t.Fatalf("Error encountered when loading config %+v", err)
+ }
+ if !config.Listeners[0].InFlightRequestLogging.UnauthenticatedInFlightAccess {
+ t.Fatalf("failed to read UnauthenticatedInFlightAccess")
+ }
+}
\ No newline at end of file
diff --git a/command/server/test-fixtures/config3.hcl b/command/server/test-fixtures/config3.hcl
index 3394d04f57f5..1a4894d194bc 100644
--- a/command/server/test-fixtures/config3.hcl
+++ b/command/server/test-fixtures/config3.hcl
@@ -1,5 +1,6 @@
disable_cache = true
disable_mlock = true
+log_requests_level = "Basic"
ui = true
diff --git a/command/server/test-fixtures/unauth_in_flight_access.hcl b/command/server/test-fixtures/unauth_in_flight_access.hcl
new file mode 100644
index 000000000000..eda6641276f1
--- /dev/null
+++ b/command/server/test-fixtures/unauth_in_flight_access.hcl
@@ -0,0 +1,9 @@
+storage "inmem" {}
+listener "tcp" {
+ address = "127.0.0.1:8200"
+ tls_disable = true
+ inflight_requests_logging {
+ unauthenticated_in_flight_requests_access = true
+ }
+}
+disable_mlock = true
diff --git a/go.mod b/go.mod
index 4c3bcc5bf4f5..1d9522817f14 100644
--- a/go.mod
+++ b/go.mod
@@ -94,7 +94,7 @@ require (
github.com/hashicorp/vault-plugin-auth-centrify v0.10.0
github.com/hashicorp/vault-plugin-auth-cf v0.10.0
github.com/hashicorp/vault-plugin-auth-gcp v0.11.2
- github.com/hashicorp/vault-plugin-auth-jwt v0.11.2
+ github.com/hashicorp/vault-plugin-auth-jwt v0.11.3
github.com/hashicorp/vault-plugin-auth-kerberos v0.5.0
github.com/hashicorp/vault-plugin-auth-kubernetes v0.11.3
github.com/hashicorp/vault-plugin-auth-oci v0.9.0
diff --git a/go.sum b/go.sum
index fa0563c53cb7..9e6374cd0dce 100644
--- a/go.sum
+++ b/go.sum
@@ -938,8 +938,8 @@ github.com/hashicorp/vault-plugin-auth-cf v0.10.0 h1:c9jepaNQXfPNl7ryufVP9RBKb5S
github.com/hashicorp/vault-plugin-auth-cf v0.10.0/go.mod h1:4HM4amMEcCyoLZNNjyz5AYILIlhMLTErxrinM3Vopy4=
github.com/hashicorp/vault-plugin-auth-gcp v0.11.2 h1:nchN/UFZDZFQbNJHDwq86vDRk6JUkTS999aZcfpxbVY=
github.com/hashicorp/vault-plugin-auth-gcp v0.11.2/go.mod h1:HJc8ih7gLNpBJYTwFlXJA3H48LKsP8mlVKYtPWfRkHs=
-github.com/hashicorp/vault-plugin-auth-jwt v0.11.2 h1:+dRT24GSDXKMF+phD+ejFDax8cI0gri6saj9p7cCXw0=
-github.com/hashicorp/vault-plugin-auth-jwt v0.11.2/go.mod h1:jzjDdssus8sw8G6NOP7kNFMEeIvrjXvPHUR3pEn5+r0=
+github.com/hashicorp/vault-plugin-auth-jwt v0.11.3 h1:uo7Gz81YqiYjg1ne4ZvT5csV/L4UT/9jlNVdCdb1jEs=
+github.com/hashicorp/vault-plugin-auth-jwt v0.11.3/go.mod h1:jzjDdssus8sw8G6NOP7kNFMEeIvrjXvPHUR3pEn5+r0=
github.com/hashicorp/vault-plugin-auth-kerberos v0.5.0 h1:oORxeqOraVVLQrb+z3fj5JayPmH/JBxJWGywZ8ZRJt0=
github.com/hashicorp/vault-plugin-auth-kerberos v0.5.0/go.mod h1:eqjae8tMBpAWgJNk1NjV/vtJYXQRZnYudUkBFowz3bY=
github.com/hashicorp/vault-plugin-auth-kubernetes v0.11.3 h1:VTl62rRNhcALzsLw8romBZfTRpVna2IeLTN0kAQyXvY=
diff --git a/helper/constants/fips.go b/helper/constants/fips.go
new file mode 100644
index 000000000000..4b8a99991c7a
--- /dev/null
+++ b/helper/constants/fips.go
@@ -0,0 +1,8 @@
+// +build !fips_140_3
+
+package constants
+
+// IsFIPS returns true if Vault is operating in a FIPS-140-{2,3} mode.
+func IsFIPS() bool {
+ return false
+}
diff --git a/http/handler.go b/http/handler.go
index 02a153eb4a0f..636566a535c5 100644
--- a/http/handler.go
+++ b/http/handler.go
@@ -25,6 +25,7 @@ import (
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-sockaddr"
+ "github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/helper/consts"
@@ -195,6 +196,11 @@ func Handler(props *vault.HandlerProperties) http.Handler {
mux.Handle("/v1/sys/pprof/", handleLogicalNoForward(core))
}
+ if props.ListenerConfig != nil && props.ListenerConfig.InFlightRequestLogging.UnauthenticatedInFlightAccess {
+ mux.Handle("/v1/sys/in-flight-req", handleUnAuthenticatedInFlightRequest(core))
+ } else {
+ mux.Handle("/v1/sys/in-flight-req", handleLogicalNoForward(core))
+ }
additionalRoutes(mux, core)
}
@@ -314,8 +320,11 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
customHeaders = listenerCustomHeaders.StatusCodeHeaderMap
}
}
+ // saving start time for the in-flight requests
+ inFlightReqStartTime := time.Now()
nw := logical.NewStatusHeaderResponseWriter(w, customHeaders)
+
// Set the Cache-Control header for all the responses returned
// by Vault
nw.Header().Set("Cache-Control", "no-store")
@@ -367,6 +376,43 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
return
}
+ // The uuid for the request is going to be generated when a logical
+ // request is generated. But, here we generate one to be able to track
+ // in-flight requests, and use that to update the req data with clientID
+ inFlightReqID, err := uuid.GenerateUUID()
+ if err != nil {
+ respondError(nw, http.StatusInternalServerError, fmt.Errorf("failed to generate an identifier for the in-flight request"))
+ }
+ // adding an entry to the context to enable updating in-flight
+ // data with ClientID in the logical layer
+ r = r.WithContext(context.WithValue(r.Context(), logical.CtxKeyInFlightRequestID{}, inFlightReqID))
+
+ // extracting the client address to be included in the in-flight request
+ var clientAddr string
+ headers := r.Header[textproto.CanonicalMIMEHeaderKey("X-Forwarded-For")]
+ if len(headers) == 0 {
+ clientAddr = r.RemoteAddr
+ } else {
+ clientAddr = headers[0]
+ }
+
+ // getting the request method
+ requestMethod := r.Method
+
+ // Storing the in-flight requests. Path should include namespace as well
+ core.StoreInFlightReqData(
+ inFlightReqID,
+ vault.InFlightReqData {
+ StartTime: inFlightReqStartTime,
+ ReqPath: r.URL.Path,
+ ClientRemoteAddr: clientAddr,
+ Method: requestMethod,
+ })
+ defer func() {
+ // Not expecting this fail, so skipping the assertion check
+ core.FinalizeInFlightReqData(inFlightReqID, nw.StatusCode)
+ }()
+
// Setting the namespace in the header to be included in the error message
ns := r.Header.Get(consts.NamespaceHeaderName)
if ns != "" {
diff --git a/http/handler_test.go b/http/handler_test.go
index b82c1ede3898..9cefe5aaa59f 100644
--- a/http/handler_test.go
+++ b/http/handler_test.go
@@ -294,6 +294,45 @@ func TestHandler_CacheControlNoStore(t *testing.T) {
}
}
+func TestHandler_InFlightRequest(t *testing.T) {
+ core, _, token := vault.TestCoreUnsealed(t)
+ ln, addr := TestServer(t, core)
+ defer ln.Close()
+ TestServerAuth(t, addr, token)
+
+ req, err := http.NewRequest("GET", addr+"/v1/sys/in-flight-req", nil)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+ req.Header.Set(consts.AuthHeaderName, token)
+
+ client := cleanhttp.DefaultClient()
+ resp, err := client.Do(req)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if resp == nil {
+ t.Fatalf("nil response")
+ }
+
+ var actual map[string]interface{}
+ testResponseStatus(t, resp, 200)
+ testResponseBody(t, resp, &actual)
+ if actual == nil || len(actual) == 0 {
+ t.Fatal("expected to get at least one in-flight request, got nil or zero length map")
+ }
+ for _, v := range actual {
+ reqInfo, ok := v.(map[string]interface{})
+ if !ok {
+ t.Fatal("failed to read in-flight request")
+ }
+ if reqInfo["request_path"] != "/v1/sys/in-flight-req" {
+ t.Fatalf("expected /v1/sys/in-flight-req in-flight request path, got %s", actual["request_path"])
+ }
+ }
+}
+
// TestHandler_MissingToken tests the response / error code if a request comes
// in with a missing client token. See
// https://github.com/hashicorp/vault/issues/8377
diff --git a/http/logical.go b/http/logical.go
index a7730033b351..4a978b2d4997 100644
--- a/http/logical.go
+++ b/http/logical.go
@@ -183,7 +183,7 @@ func buildLogicalRequestNoAuth(perfStandby bool, w http.ResponseWriter, r *http.
requestId, err := uuid.GenerateUUID()
if err != nil {
- return nil, nil, http.StatusBadRequest, fmt.Errorf("failed to generate identifier for the request: %w", err)
+ return nil, nil, http.StatusInternalServerError, fmt.Errorf("failed to generate identifier for the request: %w", err)
}
req := &logical.Request{
diff --git a/http/sys_config_state_test.go b/http/sys_config_state_test.go
index 543809ce2bd5..2abdf38e65fb 100644
--- a/http/sys_config_state_test.go
+++ b/http/sys_config_state_test.go
@@ -48,6 +48,7 @@ func TestSysConfigState_Sanitized(t *testing.T) {
"plugin_directory": "",
"enable_response_header_hostname": false,
"enable_response_header_raft_node_id": false,
+ "log_requests_level": "",
}
expected = map[string]interface{}{
diff --git a/http/sys_in_flight_requests.go b/http/sys_in_flight_requests.go
new file mode 100644
index 000000000000..cd010b2af846
--- /dev/null
+++ b/http/sys_in_flight_requests.go
@@ -0,0 +1,23 @@
+package http
+
+import (
+ "net/http"
+
+ "github.com/hashicorp/vault/vault"
+)
+
+func handleUnAuthenticatedInFlightRequest(core *vault.Core) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case "GET":
+ default:
+ respondError(w, http.StatusMethodNotAllowed, nil)
+ return
+ }
+
+ currentInFlightReqMap := core.LoadInFlightReqData()
+
+ respondOk(w, currentInFlightReqMap)
+
+ })
+}
diff --git a/http/sys_in_flight_requests_test.go b/http/sys_in_flight_requests_test.go
new file mode 100644
index 000000000000..de64d708c68f
--- /dev/null
+++ b/http/sys_in_flight_requests_test.go
@@ -0,0 +1,46 @@
+package http
+
+import (
+ "testing"
+
+ "github.com/hashicorp/vault/internalshared/configutil"
+ "github.com/hashicorp/vault/vault"
+)
+
+func TestInFlightRequestUnauthenticated(t *testing.T) {
+ conf := &vault.CoreConfig{}
+ core, _, token := vault.TestCoreUnsealedWithConfig(t, conf)
+ ln, addr := TestServer(t, core)
+ TestServerAuth(t, addr, token)
+
+ // Default: Only authenticated access
+ resp := testHttpGet(t, "", addr+"/v1/sys/in-flight-req")
+ testResponseStatus(t, resp, 403)
+ resp = testHttpGet(t, token, addr+"/v1/sys/in-flight-req")
+ testResponseStatus(t, resp, 200)
+
+ // Close listener
+ ln.Close()
+
+ // Setup new custom listener with unauthenticated metrics access
+ ln, addr = TestListener(t)
+ props := &vault.HandlerProperties{
+ Core: core,
+ ListenerConfig: &configutil.Listener{
+ InFlightRequestLogging: configutil.ListenerInFlightRequestLogging{
+ UnauthenticatedInFlightAccess: true,
+ },
+ },
+ }
+ TestServerWithListenerAndProperties(t, ln, addr, core, props)
+ defer ln.Close()
+ TestServerAuth(t, addr, token)
+
+ // Test without token
+ resp = testHttpGet(t, "", addr+"/v1/sys/in-flight-req")
+ testResponseStatus(t, resp, 200)
+
+ // Should also work with token
+ resp = testHttpGet(t, token, addr+"/v1/sys/in-flight-req")
+ testResponseStatus(t, resp, 200)
+}
diff --git a/internalshared/configutil/listener.go b/internalshared/configutil/listener.go
index 7260c9cc1f99..c4617731e282 100644
--- a/internalshared/configutil/listener.go
+++ b/internalshared/configutil/listener.go
@@ -24,9 +24,15 @@ type ListenerTelemetry struct {
}
type ListenerProfiling struct {
- UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
- UnauthenticatedPProfAccess bool `hcl:"-"`
- UnauthenticatedPProfAccessRaw interface{} `hcl:"unauthenticated_pprof_access,alias:UnauthenticatedPProfAccessRaw"`
+ UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
+ UnauthenticatedPProfAccess bool `hcl:"-"`
+ UnauthenticatedPProfAccessRaw interface{} `hcl:"unauthenticated_pprof_access,alias:UnauthenticatedPProfAccessRaw"`
+}
+
+type ListenerInFlightRequestLogging struct {
+ UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
+ UnauthenticatedInFlightAccess bool `hcl:"-"`
+ UnauthenticatedInFlightAccessRaw interface{} `hcl:"unauthenticated_in_flight_requests_access,alias:unauthenticatedInFlightAccessRaw"`
}
// Listener is the listener configuration for the server.
@@ -87,8 +93,9 @@ type Listener struct {
SocketUser string `hcl:"socket_user"`
SocketGroup string `hcl:"socket_group"`
- Telemetry ListenerTelemetry `hcl:"telemetry"`
- Profiling ListenerProfiling `hcl:"profiling"`
+ Telemetry ListenerTelemetry `hcl:"telemetry"`
+ Profiling ListenerProfiling `hcl:"profiling"`
+ InFlightRequestLogging ListenerInFlightRequestLogging `hcl:"inflight_requests_logging"`
// RandomPort is used only for some testing purposes
RandomPort bool `hcl:"-"`
@@ -345,6 +352,17 @@ func ParseListeners(result *SharedConfig, list *ast.ObjectList) error {
}
}
+ // InFlight Request logging
+ {
+ if l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw != nil {
+ if l.InFlightRequestLogging.UnauthenticatedInFlightAccess, err = parseutil.ParseBool(l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw); err != nil {
+ return multierror.Prefix(fmt.Errorf("invalid value for inflight_requests_logging.unauthenticated_in_flight_requests_access: %w", err), fmt.Sprintf("listeners.%d", i))
+ }
+
+ l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw = ""
+ }
+ }
+
// CORS
{
if l.CorsEnabledRaw != nil {
diff --git a/physical/raft/raft.go b/physical/raft/raft.go
index f88d66c5bea0..52826c09c4aa 100644
--- a/physical/raft/raft.go
+++ b/physical/raft/raft.go
@@ -1144,7 +1144,7 @@ func (b *RaftBackend) SnapshotHTTP(out *logical.HTTPResponseWriter, access *seal
// Snapshot takes a raft snapshot, packages it into a archive file and writes it
// to the provided writer. Seal access is used to encrypt the SHASUM file so we
-// can validate the snapshot was taken using the same master keys or not.
+// can validate the snapshot was taken using the same root keys or not.
func (b *RaftBackend) Snapshot(out io.Writer, access *seal.Access) error {
b.l.RLock()
defer b.l.RUnlock()
@@ -1167,7 +1167,7 @@ func (b *RaftBackend) Snapshot(out io.Writer, access *seal.Access) error {
// WriteSnapshotToTemp reads a snapshot archive off the provided reader,
// extracts the data and writes the snapshot to a temporary file. The seal
// access is used to decrypt the SHASUM file in the archive to ensure this
-// snapshot has the same master key as the running instance. If the provided
+// snapshot has the same root key as the running instance. If the provided
// access is nil then it will skip that validation.
func (b *RaftBackend) WriteSnapshotToTemp(in io.ReadCloser, access *seal.Access) (*os.File, func(), raft.SnapshotMeta, error) {
b.l.RLock()
diff --git a/scripts/docker/Dockerfile b/scripts/docker/Dockerfile
index eca04152d538..71aa724b42cf 100644
--- a/scripts/docker/Dockerfile
+++ b/scripts/docker/Dockerfile
@@ -1,7 +1,7 @@
# Multi-stage builder to avoid polluting users environment with wrong
# architecture binaries. Since this binary is used in an alpine container,
# we're explicitly compiling for 'linux/amd64'
-ARG VERSION=1.17.2
+ARG VERSION=1.17.5
FROM golang:${VERSION} AS builder
diff --git a/scripts/docker/Dockerfile.ui b/scripts/docker/Dockerfile.ui
index c8500183c69c..f49924c40c93 100644
--- a/scripts/docker/Dockerfile.ui
+++ b/scripts/docker/Dockerfile.ui
@@ -3,7 +3,7 @@
# we're explicitly compiling for 'linux/amd64'
FROM debian:buster AS builder
-ARG VERSION=1.17.2
+ARG VERSION=1.17.5
ARG CGO_ENABLED=0
ARG BUILD_TAGS
ENV JOBS=2
diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go
index 8d47d619dc28..f7bd782a2bd1 100644
--- a/sdk/helper/certutil/helpers.go
+++ b/sdk/helper/certutil/helpers.go
@@ -33,6 +33,14 @@ import (
cbasn1 "golang.org/x/crypto/cryptobyte/asn1"
)
+const rsaMinimumSecureKeySize = 2048
+
+// Mapping of key types to default key lengths
+var defaultAlgorithmKeyBits = map[string]int {
+ "rsa": 2048,
+ "ec": 256,
+}
+
// Mapping of NIST P-Curve's key length to expected signature bits.
var expectedNISTPCurveHashBits = map[int]int{
224: 256,
@@ -533,14 +541,27 @@ func StringToOid(in string) (asn1.ObjectIdentifier, error) {
return asn1.ObjectIdentifier(ret), nil
}
-// Validates that the combination of keyType, keyBits, and hashBits are
-// valid together; replaces individual calls to ValidateSignatureLength and
-// ValidateKeyTypeLength.
-func ValidateKeyTypeSignatureLength(keyType string, keyBits int, hashBits *int) error {
- if err := ValidateKeyTypeLength(keyType, keyBits); err != nil {
- return err
- }
+// Returns default key bits for the specified key type, or the present value
+// if keyBits is non-zero.
+func DefaultOrValueKeyBits(keyType string, keyBits int) (int, error) {
+ if keyBits == 0 {
+ newValue, present := defaultAlgorithmKeyBits[keyType]
+ if present {
+ keyBits = newValue
+ } /* else {
+ // We cannot return an error here as ed25519 (and potentially ed448
+ // in the future) aren't in defaultAlgorithmKeyBits -- the value of
+ // the keyBits parameter is ignored under that algorithm.
+ } */
+ }
+
+ return keyBits, nil
+}
+// Returns default signature hash bit length for the specified key type and
+// bits, or the present value if hashBits is non-zero. Returns an error under
+// certain internal circumstances.
+func DefaultOrValueHashBits(keyType string, keyBits int, hashBits int) (int, error) {
if keyType == "ec" {
// To comply with BSI recommendations Section 4.2 and Mozilla root
// store policy section 5.1.2, enforce that NIST P-curves use a hash
@@ -548,35 +569,72 @@ func ValidateKeyTypeSignatureLength(keyType string, keyBits int, hashBits *int)
// the "ec" key type.
expectedHashBits := expectedNISTPCurveHashBits[keyBits]
- if expectedHashBits != *hashBits && *hashBits != 0 {
- return fmt.Errorf("unsupported signature hash algorithm length (%d) for NIST P-%d", *hashBits, keyBits)
- } else if *hashBits == 0 {
- *hashBits = expectedHashBits
+ if expectedHashBits != hashBits && hashBits != 0 {
+ return hashBits, fmt.Errorf("unsupported signature hash algorithm length (%d) for NIST P-%d", hashBits, keyBits)
+ } else if hashBits == 0 {
+ hashBits = expectedHashBits
}
- } else if keyType == "rsa" && *hashBits == 0 {
- // To match previous behavior (and ignoring recommendations of hash
- // size to match RSA key sizes), default to SHA-2-256.
- *hashBits = 256
- } else if keyType == "ed25519" {
+ } else if keyType == "rsa" && hashBits == 0 {
+ // To match previous behavior (and ignoring NIST's recommendations for
+ // hash size to align with RSA key sizes), default to SHA-2-256.
+ hashBits = 256
+ } else if keyType == "ed25519" || keyType == "ed448" {
// No-op; ed25519 and ed448 internally specify their own hash and
// we do not need to select one. Double hashing isn't supported in
- // certificate signing.
- return nil
+ // certificate signing and we must
+ return 0, nil
+ }
+
+ return hashBits, nil
+}
+
+// Validates that the combination of keyType, keyBits, and hashBits are
+// valid together; replaces individual calls to ValidateSignatureLength and
+// ValidateKeyTypeLength. Also updates the value of keyBits and hashBits on
+// return.
+func ValidateDefaultOrValueKeyTypeSignatureLength(keyType string, keyBits int, hashBits int) (int, int, error) {
+ var err error
+
+ if keyBits, err = DefaultOrValueKeyBits(keyType, keyBits); err != nil {
+ return keyBits, hashBits, err
+ }
+
+ if err = ValidateKeyTypeLength(keyType, keyBits); err != nil {
+ return keyBits, hashBits, err
+ }
+
+ if hashBits, err = DefaultOrValueHashBits(keyType, keyBits, hashBits); err != nil {
+ return keyBits, hashBits, err
}
// Note that this check must come after we've selected a value for
// hashBits above, in the event it was left as the default, but we
// were allowed to update it.
- if err := ValidateSignatureLength(*hashBits); err != nil || *hashBits == 0 {
- return err
+ if err = ValidateSignatureLength(keyType, hashBits); err != nil {
+ return keyBits, hashBits, err
}
- return nil
+ return keyBits, hashBits, nil
}
// Validates that the length of the hash (in bits) used in the signature
// calculation is a known, approved value.
-func ValidateSignatureLength(hashBits int) error {
+func ValidateSignatureLength(keyType string, hashBits int) error {
+ if keyType == "ed25519" || keyType == "ed448" {
+ // ed25519 and ed448 include built-in hashing and is not externally
+ // configurable. There are three modes for each of these schemes:
+ //
+ // 1. Built-in hash (default, used in TLS, x509).
+ // 2. Double hash (notably used in some block-chain implementations,
+ // but largely regarded as a specialized use case with security
+ // concerns).
+ // 3. No hash (bring your own hash function, less commonly used).
+ //
+ // In all cases, we won't have a hash algorithm to validate here, so
+ // return nil.
+ return nil
+ }
+
switch hashBits {
case 256:
case 384:
@@ -584,12 +642,17 @@ func ValidateSignatureLength(hashBits int) error {
default:
return fmt.Errorf("unsupported hash signature algorithm: %d", hashBits)
}
+
return nil
}
func ValidateKeyTypeLength(keyType string, keyBits int) error {
switch keyType {
case "rsa":
+ if keyBits < rsaMinimumSecureKeySize {
+ return fmt.Errorf("RSA keys < %d bits are unsafe and not supported: got %d", rsaMinimumSecureKeySize, keyBits)
+ }
+
switch keyBits {
case 2048:
case 3072:
diff --git a/sdk/helper/keysutil/consts.go b/sdk/helper/keysutil/consts.go
index 59142a399a38..2a83ab849661 100644
--- a/sdk/helper/keysutil/consts.go
+++ b/sdk/helper/keysutil/consts.go
@@ -5,6 +5,8 @@ import (
"crypto/sha256"
"crypto/sha512"
"hash"
+
+ "golang.org/x/crypto/sha3"
)
type HashType uint32
@@ -16,6 +18,10 @@ const (
HashTypeSHA2256
HashTypeSHA2384
HashTypeSHA2512
+ HashTypeSHA3224
+ HashTypeSHA3256
+ HashTypeSHA3384
+ HashTypeSHA3512
)
type MarshalingType uint32
@@ -33,6 +39,10 @@ var (
"sha2-256": HashTypeSHA2256,
"sha2-384": HashTypeSHA2384,
"sha2-512": HashTypeSHA2512,
+ "sha3-224": HashTypeSHA3224,
+ "sha3-256": HashTypeSHA3256,
+ "sha3-384": HashTypeSHA3384,
+ "sha3-512": HashTypeSHA3512,
}
HashFuncMap = map[HashType]func() hash.Hash{
@@ -41,6 +51,10 @@ var (
HashTypeSHA2256: sha256.New,
HashTypeSHA2384: sha512.New384,
HashTypeSHA2512: sha512.New,
+ HashTypeSHA3224: sha3.New224,
+ HashTypeSHA3256: sha3.New256,
+ HashTypeSHA3384: sha3.New384,
+ HashTypeSHA3512: sha3.New512,
}
MarshalingTypeMap = map[string]MarshalingType{
diff --git a/sdk/helper/keysutil/policy.go b/sdk/helper/keysutil/policy.go
index 29fad33852c6..9ab9944b8241 100644
--- a/sdk/helper/keysutil/policy.go
+++ b/sdk/helper/keysutil/policy.go
@@ -1140,6 +1140,14 @@ func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm HashType, si
algo = crypto.SHA384
case HashTypeSHA2512:
algo = crypto.SHA512
+ case HashTypeSHA3224:
+ algo = crypto.SHA3_224
+ case HashTypeSHA3256:
+ algo = crypto.SHA3_256
+ case HashTypeSHA3384:
+ algo = crypto.SHA3_384
+ case HashTypeSHA3512:
+ algo = crypto.SHA3_512
default:
return nil, errutil.InternalError{Err: "unsupported hash algorithm"}
}
@@ -1311,6 +1319,14 @@ func (p *Policy) VerifySignature(context, input []byte, hashAlgorithm HashType,
algo = crypto.SHA384
case HashTypeSHA2512:
algo = crypto.SHA512
+ case HashTypeSHA3224:
+ algo = crypto.SHA3_224
+ case HashTypeSHA3256:
+ algo = crypto.SHA3_256
+ case HashTypeSHA3384:
+ algo = crypto.SHA3_384
+ case HashTypeSHA3512:
+ algo = crypto.SHA3_512
default:
return false, errutil.InternalError{Err: "unsupported hash algorithm"}
}
diff --git a/sdk/logical/request.go b/sdk/logical/request.go
index c44b8dd5a82c..d33290e35bde 100644
--- a/sdk/logical/request.go
+++ b/sdk/logical/request.go
@@ -382,3 +382,9 @@ type CustomHeader struct {
Name string
Value string
}
+
+type CtxKeyInFlightRequestID struct{}
+
+func (c CtxKeyInFlightRequestID) String() string {
+ return "in-flight-request-ID"
+}
\ No newline at end of file
diff --git a/sdk/logical/response.go b/sdk/logical/response.go
index 19a080c7699d..e8276c789ace 100644
--- a/sdk/logical/response.go
+++ b/sdk/logical/response.go
@@ -228,7 +228,7 @@ type WrappingResponseWriter interface {
type StatusHeaderResponseWriter struct {
wrapped http.ResponseWriter
wroteHeader bool
- statusCode int
+ StatusCode int
headers map[string][]*CustomHeader
}
@@ -236,7 +236,7 @@ func NewStatusHeaderResponseWriter(w http.ResponseWriter, h map[string][]*Custom
return &StatusHeaderResponseWriter{
wrapped: w,
wroteHeader: false,
- statusCode: 200,
+ StatusCode: 200,
headers: h,
}
}
@@ -259,7 +259,7 @@ func (w *StatusHeaderResponseWriter) Write(buf []byte) (int, error) {
// statusHeaderResponseWriter struct are called the internal call to the
// WriterHeader invoked from inside Write method won't change the headers.
if !w.wroteHeader {
- w.setCustomResponseHeaders(w.statusCode)
+ w.setCustomResponseHeaders(w.StatusCode)
}
return w.wrapped.Write(buf)
@@ -268,7 +268,7 @@ func (w *StatusHeaderResponseWriter) Write(buf []byte) (int, error) {
func (w *StatusHeaderResponseWriter) WriteHeader(statusCode int) {
w.setCustomResponseHeaders(statusCode)
w.wrapped.WriteHeader(statusCode)
- w.statusCode = statusCode
+ w.StatusCode = statusCode
// in cases where Write is called after WriteHeader, let's prevent setting
// ResponseWriter headers twice
w.wroteHeader = true
diff --git a/sdk/logical/token.go b/sdk/logical/token.go
index 0586d768ead5..b204a4a6c8dd 100644
--- a/sdk/logical/token.go
+++ b/sdk/logical/token.go
@@ -1,7 +1,11 @@
package logical
import (
+ "crypto/sha256"
+ "encoding/base64"
"fmt"
+ "sort"
+ "strings"
"time"
sockaddr "github.com/hashicorp/go-sockaddr"
@@ -20,13 +24,24 @@ const (
// TokenTypeBatch is a batch token
TokenTypeBatch
- // TokenTypeDefaultService, configured on a mount, means that if
+ // TokenTypeDefaultService configured on a mount, means that if
// TokenTypeDefault is sent back by the mount, create Service tokens
TokenTypeDefaultService
- // TokenTypeDefaultBatch, configured on a mount, means that if
+ // TokenTypeDefaultBatch configured on a mount, means that if
// TokenTypeDefault is sent back by the mount, create Batch tokens
TokenTypeDefaultBatch
+
+ // ClientIDTWEDelimiter Delimiter between the string fields used to generate a client
+ // ID for tokens without entities. This is the 0 character, which
+ // is a non-printable string. Please see unicode.IsPrint for details.
+ ClientIDTWEDelimiter = rune('\x00')
+
+ // SortedPoliciesTWEDelimiter Delimiter between each policy in the sorted policies used to
+ // generate a client ID for tokens without entities. This is the 127
+ // character, which is a non-printable string. Please see unicode.IsPrint
+ // for details.
+ SortedPoliciesTWEDelimiter = rune('\x7F')
)
func (t *TokenType) UnmarshalJSON(b []byte) error {
@@ -154,6 +169,46 @@ type TokenEntry struct {
CubbyholeID string `json:"cubbyhole_id" mapstructure:"cubbyhole_id" structs:"cubbyhole_id" sentinel:""`
}
+// CreateClientID returns the client ID, and a boolean which is false if the clientID
+// has an entity, and true otherwise
+func (te *TokenEntry) CreateClientID() (string, bool) {
+ var clientIDInputBuilder strings.Builder
+
+ // if entry has an associated entity ID, return it
+ if te.EntityID != "" {
+ return te.EntityID, false
+ }
+
+ // The entry is associated with a TWE (token without entity). In this case
+ // we must create a client ID by calculating the following formula:
+ // clientID = SHA256(sorted policies + namespace)
+
+ // Step 1: Copy entry policies to a new struct
+ sortedPolicies := make([]string, len(te.Policies))
+ copy(sortedPolicies, te.Policies)
+
+ // Step 2: Sort and join copied policies
+ sort.Strings(sortedPolicies)
+ for _, pol := range sortedPolicies {
+ clientIDInputBuilder.WriteRune(SortedPoliciesTWEDelimiter)
+ clientIDInputBuilder.WriteString(pol)
+ }
+
+ // Step 3: Add namespace ID
+ clientIDInputBuilder.WriteRune(ClientIDTWEDelimiter)
+ clientIDInputBuilder.WriteString(te.NamespaceID)
+
+ if clientIDInputBuilder.Len() == 0 {
+ return "", true
+ }
+ // Step 4: Remove the first character in the string, as it's an unnecessary delimiter
+ clientIDInput := clientIDInputBuilder.String()[1:]
+
+ // Step 5: Hash the sum
+ hashed := sha256.Sum256([]byte(clientIDInput))
+ return base64.StdEncoding.EncodeToString(hashed[:]), true
+}
+
func (te *TokenEntry) SentinelGet(key string) (interface{}, error) {
if te == nil {
return nil, nil
diff --git a/sdk/logical/token_test.go b/sdk/logical/token_test.go
index 5499e5c5bd14..e44c707a5165 100644
--- a/sdk/logical/token_test.go
+++ b/sdk/logical/token_test.go
@@ -1,6 +1,8 @@
package logical
import (
+ "crypto/sha256"
+ "encoding/base64"
"encoding/json"
"testing"
)
@@ -41,3 +43,61 @@ func TestJSONSerialization(t *testing.T) {
t.Fatalf("expected %v, got %v", tt, utt)
}
}
+
+// TestCreateClientID verifies that CreateClientID uses the entity ID for a token
+// entry if one exists, and creates an appropriate client ID otherwise.
+func TestCreateClientID(t *testing.T) {
+ entry := TokenEntry{NamespaceID: "namespaceFoo", Policies: []string{"bar", "baz", "foo", "banana"}}
+ id, isTWE := entry.CreateClientID()
+ if !isTWE {
+ t.Fatalf("TWE token should return true value in isTWE bool")
+ }
+ expectedIDPlaintext := "banana" + string(SortedPoliciesTWEDelimiter) + "bar" +
+ string(SortedPoliciesTWEDelimiter) + "baz" +
+ string(SortedPoliciesTWEDelimiter) + "foo" + string(ClientIDTWEDelimiter) + "namespaceFoo"
+
+ hashed := sha256.Sum256([]byte(expectedIDPlaintext))
+ expectedID := base64.StdEncoding.EncodeToString(hashed[:])
+ if expectedID != id {
+ t.Fatalf("wrong ID: expected %s, found %s", expectedID, id)
+ }
+ // Test with entityID
+ entry = TokenEntry{EntityID: "entityFoo", NamespaceID: "namespaceFoo", Policies: []string{"bar", "baz", "foo", "banana"}}
+ id, isTWE = entry.CreateClientID()
+ if isTWE {
+ t.Fatalf("token with entity should return false value in isTWE bool")
+ }
+ if id != "entityFoo" {
+ t.Fatalf("client ID should be entity ID")
+ }
+
+ // Test without namespace
+ entry = TokenEntry{Policies: []string{"bar", "baz", "foo", "banana"}}
+ id, isTWE = entry.CreateClientID()
+ if !isTWE {
+ t.Fatalf("TWE token should return true value in isTWE bool")
+ }
+ expectedIDPlaintext = "banana" + string(SortedPoliciesTWEDelimiter) + "bar" +
+ string(SortedPoliciesTWEDelimiter) + "baz" +
+ string(SortedPoliciesTWEDelimiter) + "foo" + string(ClientIDTWEDelimiter)
+
+ hashed = sha256.Sum256([]byte(expectedIDPlaintext))
+ expectedID = base64.StdEncoding.EncodeToString(hashed[:])
+ if expectedID != id {
+ t.Fatalf("wrong ID: expected %s, found %s", expectedID, id)
+ }
+
+ // Test without policies
+ entry = TokenEntry{NamespaceID: "namespaceFoo"}
+ id, isTWE = entry.CreateClientID()
+ if !isTWE {
+ t.Fatalf("TWE token should return true value in isTWE bool")
+ }
+ expectedIDPlaintext = "namespaceFoo"
+
+ hashed = sha256.Sum256([]byte(expectedIDPlaintext))
+ expectedID = base64.StdEncoding.EncodeToString(hashed[:])
+ if expectedID != id {
+ t.Fatalf("wrong ID: expected %s, found %s", expectedID, id)
+ }
+}
diff --git a/ui/.storybook/config.js b/ui/.storybook/config.js
index 3a9556ab25be..23f4116d6c8d 100644
--- a/ui/.storybook/config.js
+++ b/ui/.storybook/config.js
@@ -1,6 +1,7 @@
import { configure, addParameters, addDecorator } from '@storybook/ember';
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import theme from './theme.js';
+import flightIconSprite from '@hashicorp/flight-icons/svg-sprite/svg-sprite-module';
function loadStories() {
// automatically import all files ending in *.stories.js
@@ -18,6 +19,9 @@ addParameters({
addDecorator(storyFn => {
const { template, context } = storyFn();
+ // flight icon sprite must be inserted into dom for icon lookup via use element
+ document.getElementById('root').insertAdjacentHTML('afterbegin', flightIconSprite.trim());
+
// This adds styling to the Canvas tab.
const styles = {
style: {
diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js
index 1fba7edc239f..57e6154f22a9 100644
--- a/ui/app/components/clients/dashboard.js
+++ b/ui/app/components/clients/dashboard.js
@@ -13,11 +13,11 @@ export default class Dashboard extends Component {
@tracked barChartSelection = false;
- // Determine if we have client count data based on the current tab,
- // since model is slightly different for current month vs history api
+ // Determine if we have client count data based on the current tab
get hasClientData() {
if (this.args.tab === 'current') {
- return this.args.model.activity && this.args.model.activity.clients;
+ // Show the current numbers as long as config is on
+ return this.args.model.config?.enabled !== 'Off';
}
return this.args.model.activity && this.args.model.activity.total;
}
diff --git a/ui/app/components/regex-validator.hbs b/ui/app/components/regex-validator.hbs
index 18c5cf64fbeb..4b38e7a676fc 100644
--- a/ui/app/components/regex-validator.hbs
+++ b/ui/app/components/regex-validator.hbs
@@ -57,7 +57,7 @@
{{else}}
-
+
Your regex matches the subject string
{{/if}}
diff --git a/ui/app/components/status-menu.js b/ui/app/components/status-menu.js
index 59bfc2bcf98b..8aa4e182e344 100644
--- a/ui/app/components/status-menu.js
+++ b/ui/app/components/status-menu.js
@@ -11,10 +11,9 @@ export default Component.extend({
type: 'cluster',
itemTag: null,
glyphName: computed('type', function() {
- const glyphs = {
- cluster: 'status-indicator',
- user: 'user-square-outline',
- };
- return glyphs[this.type];
+ return {
+ cluster: 'circle-dot',
+ user: 'user',
+ }[this.type];
}),
});
diff --git a/ui/app/components/toolbar-secret-link.js b/ui/app/components/toolbar-secret-link.js
index 00395ccabd4a..08318b86f629 100644
--- a/ui/app/components/toolbar-secret-link.js
+++ b/ui/app/components/toolbar-secret-link.js
@@ -23,7 +23,7 @@ import { computed } from '@ember/object';
export default OuterHTML.extend({
glyph: computed('type', function() {
if (this.type == 'add') {
- return 'plus-plain';
+ return 'plus';
} else {
return 'chevron-right';
}
diff --git a/ui/app/models/transit-key.js b/ui/app/models/transit-key.js
index ffb203c74829..09c6f47de272 100644
--- a/ui/app/models/transit-key.js
+++ b/ui/app/models/transit-key.js
@@ -8,12 +8,12 @@ const ACTION_VALUES = {
encrypt: {
isSupported: 'supportsEncryption',
description: 'Looks up wrapping properties for the given token',
- glyph: 'lock-closed',
+ glyph: 'lock-fill',
},
decrypt: {
isSupported: 'supportsDecryption',
description: 'Decrypts the provided ciphertext using this key',
- glyph: 'envelope-unsealed--outline',
+ glyph: 'mail-open',
},
datakey: {
isSupported: 'supportsEncryption',
@@ -23,20 +23,28 @@ const ACTION_VALUES = {
rewrap: {
isSupported: 'supportsEncryption',
description: 'Rewraps the ciphertext using the latest version of the named key',
- glyph: 'refresh-default',
+ glyph: 'reload',
},
sign: {
isSupported: 'supportsSigning',
description: 'Get the cryptographic signature of the given data',
- glyph: 'edit',
+ glyph: 'pencil-tool',
+ },
+ hmac: {
+ isSupported: true,
+ description: 'Generate a data digest using a hash algorithm',
+ glyph: 'shuffle',
},
- hmac: { isSupported: true, description: 'Generate a data digest using a hash algorithm', glyph: 'remix' },
verify: {
isSupported: true,
description: 'Validate the provided signature for the given data',
- glyph: 'check-circle-outline',
+ glyph: 'check-circle',
+ },
+ export: {
+ isSupported: 'exportable',
+ description: 'Get the named key',
+ glyph: 'external-link',
},
- export: { isSupported: 'exportable', description: 'Get the named key', glyph: 'exit' },
};
export default Model.extend({
diff --git a/ui/app/routes/vault/cluster.js b/ui/app/routes/vault/cluster.js
index ce4d17ff0014..c9b1c150f4d8 100644
--- a/ui/app/routes/vault/cluster.js
+++ b/ui/app/routes/vault/cluster.js
@@ -40,8 +40,8 @@ export default Route.extend(ModelBoundaryRoute, ClusterRoute, {
const currentTokenName = this.auth.get('currentTokenName');
// if no namespace queryParam and user authenticated,
// use user's root namespace to redirect to properly param'd url
- if (this.featureFlagService.managedNamespaceRoot && !this.version.hasNamespaces) {
- window.alert('Cannot use Cloud Admin Namespace flag with OSS Vault');
+ if (this.featureFlagService.managedNamespaceRoot && this.version.isOss) {
+ console.error('Cannot use Cloud Admin Namespace flag with OSS Vault');
}
if (!namespace && currentTokenName && !Ember.testing) {
const storage = getStorage().getItem(currentTokenName);
diff --git a/ui/app/styles/components/console-ui-panel.scss b/ui/app/styles/components/console-ui-panel.scss
index 170af92dec9b..1542dcaec7ad 100644
--- a/ui/app/styles/components/console-ui-panel.scss
+++ b/ui/app/styles/components/console-ui-panel.scss
@@ -106,7 +106,7 @@
margin-left: calc(#{$console-spacing} - 0.33rem);
position: relative;
- .hs-icon {
+ svg {
position: absolute;
left: 0;
top: 0;
diff --git a/ui/app/styles/components/hs-icon.scss b/ui/app/styles/components/icon.scss
similarity index 84%
rename from ui/app/styles/components/hs-icon.scss
rename to ui/app/styles/components/icon.scss
index 80507831ec47..e60da0533798 100644
--- a/ui/app/styles/components/hs-icon.scss
+++ b/ui/app/styles/components/icon.scss
@@ -43,3 +43,10 @@
width: 32px;
height: 32px;
}
+
+.flight-icon {
+ &.flight-icon-display-inline {
+ vertical-align: middle;
+ margin: 0px 4px;
+ }
+}
diff --git a/ui/app/styles/core.scss b/ui/app/styles/core.scss
index 6ec797e43dda..7d91d8efd9af 100644
--- a/ui/app/styles/core.scss
+++ b/ui/app/styles/core.scss
@@ -121,4 +121,4 @@
@import './components/vlt-table';
// bulma-free-zone
-@import './components/hs-icon';
+@import './components/icon';
diff --git a/ui/app/templates/components/alert-popup.hbs b/ui/app/templates/components/alert-popup.hbs
index c6d73c1fa9ef..389c1eeaa065 100644
--- a/ui/app/templates/components/alert-popup.hbs
+++ b/ui/app/templates/components/alert-popup.hbs
@@ -3,16 +3,12 @@
-
+
{{type.text}}
diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs
index ec5d327747ac..845c4a2fcb2d 100644
--- a/ui/app/templates/components/clients/dashboard.hbs
+++ b/ui/app/templates/components/clients/dashboard.hbs
@@ -1,4 +1,4 @@
-{{#if (eq @model.config.queriesAvailable false)}}
+{{#if (and (eq @tab 'history') (eq @model.config.queriesAvailable false))}}
{{#if (eq @model.config.enabled 'On')}}
@@ -116,7 +116,7 @@
@@ -125,7 +125,7 @@
diff --git a/ui/app/templates/components/cluster-info.hbs b/ui/app/templates/components/cluster-info.hbs
index c404841d7f39..17e3ff1ca7f6 100644
--- a/ui/app/templates/components/cluster-info.hbs
+++ b/ui/app/templates/components/cluster-info.hbs
@@ -27,7 +27,7 @@
Enable
-
+
@@ -66,14 +66,14 @@
Unsealed
-
+
{{else}}
{{/if}}
@@ -81,7 +81,7 @@
{{/if}}
diff --git a/ui/app/templates/components/console/command-input.hbs b/ui/app/templates/components/console/command-input.hbs
index ab4be479e1e5..4d666b3507e6 100644
--- a/ui/app/templates/components/console/command-input.hbs
+++ b/ui/app/templates/components/console/command-input.hbs
@@ -7,7 +7,10 @@
-
+
diff --git a/ui/app/templates/components/console/log-command.hbs b/ui/app/templates/components/console/log-command.hbs
index cc446877d8dd..87700e2e2530 100644
--- a/ui/app/templates/components/console/log-command.hbs
+++ b/ui/app/templates/components/console/log-command.hbs
@@ -1,2 +1,2 @@
{{!-- using Icon here instead of Chevron because two nested tagless components results in a rendered line break between the tags breaking the layout in the
--}}
- {{content}}
+ {{content}}
diff --git a/ui/app/templates/components/console/log-error-with-html.hbs b/ui/app/templates/components/console/log-error-with-html.hbs
index 45e0c4540d24..bff73bf39d8e 100644
--- a/ui/app/templates/components/console/log-error-with-html.hbs
+++ b/ui/app/templates/components/console/log-error-with-html.hbs
@@ -1,5 +1,5 @@
{{! template-lint-disable no-triple-curlies}}
diff --git a/ui/app/templates/components/console/log-error.hbs b/ui/app/templates/components/console/log-error.hbs
index 11cd2647b2a5..60a2dad428de 100644
--- a/ui/app/templates/components/console/log-error.hbs
+++ b/ui/app/templates/components/console/log-error.hbs
@@ -1,4 +1,4 @@
diff --git a/ui/app/templates/components/console/log-help.hbs b/ui/app/templates/components/console/log-help.hbs
index 6d9aa8419fcd..09e6c3cb1cf2 100644
--- a/ui/app/templates/components/console/log-help.hbs
+++ b/ui/app/templates/components/console/log-help.hbs
@@ -1,5 +1,5 @@
-
+
Usage: vault <command> [args]
Commands:
diff --git a/ui/app/templates/components/console/log-success.hbs b/ui/app/templates/components/console/log-success.hbs
index d5bcaa7b05b4..5c0bb8a0b8d5 100644
--- a/ui/app/templates/components/console/log-success.hbs
+++ b/ui/app/templates/components/console/log-success.hbs
@@ -1,4 +1,4 @@
diff --git a/ui/app/templates/components/console/ui-panel.hbs b/ui/app/templates/components/console/ui-panel.hbs
index 8af5abaa04b9..fae0f8f58d6f 100644
--- a/ui/app/templates/components/console/ui-panel.hbs
+++ b/ui/app/templates/components/console/ui-panel.hbs
@@ -1,5 +1,5 @@
-
+
diff --git a/ui/app/templates/components/control-group.hbs b/ui/app/templates/components/control-group.hbs
index fc5ff421e4e7..04ea9b0f0d12 100644
--- a/ui/app/templates/components/control-group.hbs
+++ b/ui/app/templates/components/control-group.hbs
@@ -2,7 +2,7 @@
diff --git a/ui/app/templates/components/pgp-file.hbs b/ui/app/templates/components/pgp-file.hbs
index e8ee3c7f0ca7..4d5811d384d8 100644
--- a/ui/app/templates/components/pgp-file.hbs
+++ b/ui/app/templates/components/pgp-file.hbs
@@ -48,7 +48,7 @@
-
+
{{#if key.fileName}}
@@ -59,10 +59,7 @@
{{#if key.fileName}}
-
+
{{/if}}
diff --git a/ui/app/templates/components/raft-storage-overview.hbs b/ui/app/templates/components/raft-storage-overview.hbs
index 4a75006b4a58..20a605278cac 100644
--- a/ui/app/templates/components/raft-storage-overview.hbs
+++ b/ui/app/templates/components/raft-storage-overview.hbs
@@ -69,17 +69,15 @@
{{#if server.voter}}
{{else}}
{{/if}}
diff --git a/ui/app/templates/components/secret-create-or-update.hbs b/ui/app/templates/components/secret-create-or-update.hbs
index 965a4039371a..bfccd5fb73ca 100644
--- a/ui/app/templates/components/secret-create-or-update.hbs
+++ b/ui/app/templates/components/secret-create-or-update.hbs
@@ -88,8 +88,7 @@
aria-label="Delete row"
>
@@ -220,8 +219,7 @@
aria-label="Delete row"
>
diff --git a/ui/app/templates/components/secret-form-show.hbs b/ui/app/templates/components/secret-form-show.hbs
index 3f0c3eb7682d..0d992f9888e9 100644
--- a/ui/app/templates/components/secret-form-show.hbs
+++ b/ui/app/templates/components/secret-form-show.hbs
@@ -67,14 +67,14 @@
{{#if secret.value}}
{{else}}
-
+
{{/if}}
{{/each}}
{{else}}
{{!-- In the case of no key or value
will still render --}}
-
+
{{/if}}
{{/if}}
diff --git a/ui/app/templates/components/secret-list-header.hbs b/ui/app/templates/components/secret-list-header.hbs
index 25aca00c09cd..6a8b12948f68 100644
--- a/ui/app/templates/components/secret-list-header.hbs
+++ b/ui/app/templates/components/secret-list-header.hbs
@@ -14,7 +14,7 @@
-
+
{{@model.id}}
{{#if this.isKV}}
diff --git a/ui/app/templates/components/secret-list/aws-role-item.hbs b/ui/app/templates/components/secret-list/aws-role-item.hbs
index d013fd95d77c..c5d4361b66ee 100644
--- a/ui/app/templates/components/secret-list/aws-role-item.hbs
+++ b/ui/app/templates/components/secret-list/aws-role-item.hbs
@@ -13,7 +13,7 @@
diff --git a/ui/app/templates/components/secret-list/database-list-item.hbs b/ui/app/templates/components/secret-list/database-list-item.hbs
index 3f1c3da9df24..9808f5702c96 100644
--- a/ui/app/templates/components/secret-list/database-list-item.hbs
+++ b/ui/app/templates/components/secret-list/database-list-item.hbs
@@ -15,7 +15,7 @@
class="has-text-black has-text-weight-semibold"
>
diff --git a/ui/app/templates/components/secret-list/item.hbs b/ui/app/templates/components/secret-list/item.hbs
index 36bf9baefe1e..6e56610630a9 100644
--- a/ui/app/templates/components/secret-list/item.hbs
+++ b/ui/app/templates/components/secret-list/item.hbs
@@ -18,9 +18,9 @@
@queryParams={{if (eq @backendModel.type "transit") (query-params tab="actions") ""}}
@class="has-text-black has-text-weight-semibold">
{{#if (eq @backendModel.type "transit")}}
-
+
{{else}}
-
+
{{/if}}
{{if (eq @item.id ' ') '(self)' (or @item.keyWithoutParent @item.id)}}
diff --git a/ui/app/templates/components/secret-list/pki-cert-item.hbs b/ui/app/templates/components/secret-list/pki-cert-item.hbs
index bcea13c12132..799a11680b4f 100644
--- a/ui/app/templates/components/secret-list/pki-cert-item.hbs
+++ b/ui/app/templates/components/secret-list/pki-cert-item.hbs
@@ -14,7 +14,7 @@
diff --git a/ui/app/templates/components/secret-list/pki-role-item.hbs b/ui/app/templates/components/secret-list/pki-role-item.hbs
index 985255c18e2d..fef744578052 100644
--- a/ui/app/templates/components/secret-list/pki-role-item.hbs
+++ b/ui/app/templates/components/secret-list/pki-role-item.hbs
@@ -16,7 +16,7 @@
diff --git a/ui/app/templates/components/secret-list/ssh-role-item.hbs b/ui/app/templates/components/secret-list/ssh-role-item.hbs
index f64793f93cb5..db34a7699989 100644
--- a/ui/app/templates/components/secret-list/ssh-role-item.hbs
+++ b/ui/app/templates/components/secret-list/ssh-role-item.hbs
@@ -13,7 +13,7 @@
diff --git a/ui/app/templates/components/secret-list/transform-list-item.hbs b/ui/app/templates/components/secret-list/transform-list-item.hbs
index bb0574ad210d..5fc3d4c2c85d 100644
--- a/ui/app/templates/components/secret-list/transform-list-item.hbs
+++ b/ui/app/templates/components/secret-list/transform-list-item.hbs
@@ -13,10 +13,9 @@
@mode="show"
@secret={{@itemPath}}
@queryParams={{query-params type=@modelType}}
- @class="has-text-black has-text-weight-semibold">
-
+ @class="has-text-black has-text-weight-semibold"
+ >
+
{{if (eq @item.id ' ') '(self)' (or @item.keyWithoutParent @item.id)}}
@@ -56,9 +55,7 @@
-
+
{{#if this.isBuiltin}}
-
+ @class="has-text-black has-text-weight-semibold"
+ >
+
{{if (eq @item.id ' ') '(self)' (or @item.keyWithoutParent @item.id)}}
@@ -65,9 +64,7 @@
-
+
{{if (eq @item.id ' ') '(self)' (or @item.keyWithoutParent @item.id)}}
diff --git a/ui/app/templates/components/secret-version-menu.hbs b/ui/app/templates/components/secret-version-menu.hbs
index 2867800e8a63..5c560ce796a3 100644
--- a/ui/app/templates/components/secret-version-menu.hbs
+++ b/ui/app/templates/components/secret-version-menu.hbs
@@ -23,11 +23,11 @@
Version {{secretVersion.version}}
{{#if (and (eq secretVersion.version @model.currentVersion) (not secretVersion.destroyed) (not secretVersion.deleted))}}
-
+
{{else if secretVersion.destroyed}}
-
+
{{else if secretVersion.deleted}}
-
+
{{/if}}
diff --git a/ui/app/templates/components/selectable-card.hbs b/ui/app/templates/components/selectable-card.hbs
index 8062781d84d2..9080e691c3b7 100644
--- a/ui/app/templates/components/selectable-card.hbs
+++ b/ui/app/templates/components/selectable-card.hbs
@@ -26,7 +26,9 @@
data-test-action-text={{actionText}}
>
{{actionText}}
- {{#if actionText}}
{{/if}}
+ {{#if actionText}}
+
+ {{/if}}
{{subText}}
diff --git a/ui/app/templates/components/status-menu.hbs b/ui/app/templates/components/status-menu.hbs
index 85b9a52f1d6b..b2d3a1408169 100644
--- a/ui/app/templates/components/status-menu.hbs
+++ b/ui/app/templates/components/status-menu.hbs
@@ -1,6 +1,6 @@
-
+
diff --git a/ui/app/templates/components/text-file.hbs b/ui/app/templates/components/text-file.hbs
index fab1724a0910..94dce03cb632 100644
--- a/ui/app/templates/components/text-file.hbs
+++ b/ui/app/templates/components/text-file.hbs
@@ -47,7 +47,7 @@
type="button"
class="{{if (eq value "") "has-text-grey"}} masked-input-toggle button {{if displayOnly "is-compact"}}"
data-test-button>
-
+
@@ -59,7 +59,7 @@
-
+
Choose a file…
@@ -71,7 +71,7 @@
{{#if @file.fileName}}
-
+
{{/if}}
diff --git a/ui/app/templates/components/tool-unwrap.hbs b/ui/app/templates/components/tool-unwrap.hbs
index fc5f2ae22e09..dc61f27b208f 100644
--- a/ui/app/templates/components/tool-unwrap.hbs
+++ b/ui/app/templates/components/tool-unwrap.hbs
@@ -31,10 +31,11 @@
{{#each-in @details as |key detail|}}
{{#if (or (eq detail "No") (eq detail "None"))}}
- {{detail}}
+
+ {{detail}}
{{else}}
{{#if (eq detail "Yes") }}
-
+
{{/if}}
{{detail}}
{{/if}}
diff --git a/ui/app/templates/components/toolbar-secret-link.hbs b/ui/app/templates/components/toolbar-secret-link.hbs
index f406edc0f41c..ce41009503b7 100644
--- a/ui/app/templates/components/toolbar-secret-link.hbs
+++ b/ui/app/templates/components/toolbar-secret-link.hbs
@@ -14,5 +14,5 @@
@data-test-transit-key-actions-link={{data-test-transit-key-actions-link}}
>
{{yield}}
-
+
diff --git a/ui/app/templates/components/transform-show-transformation.hbs b/ui/app/templates/components/transform-show-transformation.hbs
index 5d989c52b33c..18f6d8df43f7 100644
--- a/ui/app/templates/components/transform-show-transformation.hbs
+++ b/ui/app/templates/components/transform-show-transformation.hbs
@@ -24,7 +24,7 @@
vault write {{model.backend}}/encode/{{cliCommand}}
-
+
{{/let}}
@@ -41,7 +41,7 @@
vault write {{model.backend}}/decode/{{cliCommand}}
-
+
{{/let}}
diff --git a/ui/app/templates/components/transit-form-show.hbs b/ui/app/templates/components/transit-form-show.hbs
index 56c7f3e3c01e..89f53c49ac77 100644
--- a/ui/app/templates/components/transit-form-show.hbs
+++ b/ui/app/templates/components/transit-form-show.hbs
@@ -59,10 +59,10 @@
}}
+ aria-label={{concat @backend.path " options"}}
+ />
@@ -91,7 +91,10 @@
@@ -106,7 +109,7 @@
{{#if (coerce-eq @key.minDecryptionVersion version)}}
-
+
Current minimum decryption version
{{/if}}
@@ -121,7 +124,10 @@
@@ -136,7 +142,7 @@
{{#if (coerce-eq @key.minDecryptionVersion version)}}
-
+
Current minimum decryption version
{{/if}}
diff --git a/ui/app/templates/components/transit-key-action/datakey.hbs b/ui/app/templates/components/transit-key-action/datakey.hbs
index fcd96e6fc8ec..9312b7b29006 100644
--- a/ui/app/templates/components/transit-key-action/datakey.hbs
+++ b/ui/app/templates/components/transit-key-action/datakey.hbs
@@ -86,7 +86,7 @@
{{@plaintext}}
-
+
Plaintext is base64 encoded
@@ -95,7 +95,7 @@
{{@ciphertext}}
-
+
{{@ciphertext}}
-
+
{{@plaintext}}
-
+
Plaintext is base64 encoded
diff --git a/ui/app/templates/components/transit-key-action/encrypt.hbs b/ui/app/templates/components/transit-key-action/encrypt.hbs
index 1293fe9cc709..5dfab7bbd309 100644
--- a/ui/app/templates/components/transit-key-action/encrypt.hbs
+++ b/ui/app/templates/components/transit-key-action/encrypt.hbs
@@ -75,7 +75,7 @@
@clipboardText={{@ciphertext}}
@buttonType="button"
@success={{action (set-flash-message 'Ciphertext copied!')}}>
-
+
diff --git a/ui/app/templates/components/transit-key-action/export.hbs b/ui/app/templates/components/transit-key-action/export.hbs
index 9c137aedd891..c9dcd1b791fa 100644
--- a/ui/app/templates/components/transit-key-action/export.hbs
+++ b/ui/app/templates/components/transit-key-action/export.hbs
@@ -73,7 +73,7 @@
{{if this.wrapTTL @wrappedToken (stringify @keys)}}
-
+
diff --git a/ui/app/templates/components/transit-key-action/hmac.hbs b/ui/app/templates/components/transit-key-action/hmac.hbs
index edc606024cf9..25ed773a292a 100644
--- a/ui/app/templates/components/transit-key-action/hmac.hbs
+++ b/ui/app/templates/components/transit-key-action/hmac.hbs
@@ -55,7 +55,7 @@
{{@hmac}}
-
+
diff --git a/ui/app/templates/components/transit-key-action/rewrap.hbs b/ui/app/templates/components/transit-key-action/rewrap.hbs
index 26b0f39d4266..f0abf4a0bfaa 100644
--- a/ui/app/templates/components/transit-key-action/rewrap.hbs
+++ b/ui/app/templates/components/transit-key-action/rewrap.hbs
@@ -66,7 +66,7 @@
{{@ciphertext}}
-
+
diff --git a/ui/app/templates/components/transit-key-action/sign.hbs b/ui/app/templates/components/transit-key-action/sign.hbs
index 7917be963f57..aa9da07d8b6e 100644
--- a/ui/app/templates/components/transit-key-action/sign.hbs
+++ b/ui/app/templates/components/transit-key-action/sign.hbs
@@ -110,7 +110,7 @@
@clipboardText={{@signature}}
@buttonType="button"
@success={{action (set-flash-message 'Signature copied!')}}>
-
+
diff --git a/ui/app/templates/components/wizard-content.hbs b/ui/app/templates/components/wizard-content.hbs
index 1637c1ac0a7b..62cb90706643 100644
--- a/ui/app/templates/components/wizard-content.hbs
+++ b/ui/app/templates/components/wizard-content.hbs
@@ -13,7 +13,7 @@
{{/unless}}
- {{headerText}}
+ {{headerText}}
{{#if showProgress}}
diff --git a/ui/app/templates/components/wizard-progress.hbs b/ui/app/templates/components/wizard-progress.hbs
index e4de36e03433..e0879fcce62d 100644
--- a/ui/app/templates/components/wizard-progress.hbs
+++ b/ui/app/templates/components/wizard-progress.hbs
@@ -6,7 +6,10 @@
{{#if bar.showIcon}}
-
+
{{/if}}
{{/each}}
diff --git a/ui/app/templates/components/wizard-section.hbs b/ui/app/templates/components/wizard-section.hbs
index 9871432428b0..20f2166f4e54 100644
--- a/ui/app/templates/components/wizard-section.hbs
+++ b/ui/app/templates/components/wizard-section.hbs
@@ -1,7 +1,7 @@
{{#if headerIcon}}
-
+
{{/if}}
{{headerText}}
@@ -14,7 +14,7 @@
{{/if}}
{{#if docText}}
- {{docText}}
+ {{docText}}
{{/if}}
diff --git a/ui/app/templates/components/wizard/ad-engine.hbs b/ui/app/templates/components/wizard/ad-engine.hbs
index 027e078c725d..492b51a4ef48 100644
--- a/ui/app/templates/components/wizard/ad-engine.hbs
+++ b/ui/app/templates/components/wizard/ad-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/alicloud-engine.hbs b/ui/app/templates/components/wizard/alicloud-engine.hbs
index 41e25e764b57..bf23863f166d 100644
--- a/ui/app/templates/components/wizard/alicloud-engine.hbs
+++ b/ui/app/templates/components/wizard/alicloud-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/alicloud-method.hbs b/ui/app/templates/components/wizard/alicloud-method.hbs
index 0f4c92c23d6d..383f059cadc8 100644
--- a/ui/app/templates/components/wizard/alicloud-method.hbs
+++ b/ui/app/templates/components/wizard/alicloud-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/approle-method.hbs b/ui/app/templates/components/wizard/approle-method.hbs
index c47898c687c2..a058962dc3a6 100644
--- a/ui/app/templates/components/wizard/approle-method.hbs
+++ b/ui/app/templates/components/wizard/approle-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/auth-details.hbs b/ui/app/templates/components/wizard/auth-details.hbs
index d0514a48e2f5..061fc631e548 100644
--- a/ui/app/templates/components/wizard/auth-details.hbs
+++ b/ui/app/templates/components/wizard/auth-details.hbs
@@ -12,7 +12,7 @@
@class="wizard-details"
>
- Enable another Auth Method
+ Enable another Auth Method
{{@nextFeature}}
diff --git a/ui/app/templates/components/wizard/aws-engine.hbs b/ui/app/templates/components/wizard/aws-engine.hbs
index 61306c7dcf2c..8524fbc5bd2b 100644
--- a/ui/app/templates/components/wizard/aws-engine.hbs
+++ b/ui/app/templates/components/wizard/aws-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/aws-method.hbs b/ui/app/templates/components/wizard/aws-method.hbs
index 2877a37e451a..70ca72a3bcc5 100644
--- a/ui/app/templates/components/wizard/aws-method.hbs
+++ b/ui/app/templates/components/wizard/aws-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/azure-engine.hbs b/ui/app/templates/components/wizard/azure-engine.hbs
index e4029fa89456..18d2d945a710 100644
--- a/ui/app/templates/components/wizard/azure-engine.hbs
+++ b/ui/app/templates/components/wizard/azure-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/azure-method.hbs b/ui/app/templates/components/wizard/azure-method.hbs
index 6d652b242c9b..e72e0b53b0bd 100644
--- a/ui/app/templates/components/wizard/azure-method.hbs
+++ b/ui/app/templates/components/wizard/azure-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/cert-method.hbs b/ui/app/templates/components/wizard/cert-method.hbs
index ea797aa45bfe..80b1f028eeae 100644
--- a/ui/app/templates/components/wizard/cert-method.hbs
+++ b/ui/app/templates/components/wizard/cert-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/features-selection.hbs b/ui/app/templates/components/wizard/features-selection.hbs
index 331728151850..f8cc4ded12f8 100644
--- a/ui/app/templates/components/wizard/features-selection.hbs
+++ b/ui/app/templates/components/wizard/features-selection.hbs
@@ -4,7 +4,7 @@
You did it! You now have access to your Vault and can start entering your data. We can help you get started with any of the options below.
{{#if (or (has-feature "Performance Replication") (has-feature "DR Replication")) }}
@@ -58,7 +58,9 @@
Start
{{#if selectedFeatures}}
- About {{estimatedTime}} minutes
+
+ About {{estimatedTime}} minutes
+
{{/if}}
diff --git a/ui/app/templates/components/wizard/gcp-engine.hbs b/ui/app/templates/components/wizard/gcp-engine.hbs
index e61ced1f421a..89cf14d8d9d9 100644
--- a/ui/app/templates/components/wizard/gcp-engine.hbs
+++ b/ui/app/templates/components/wizard/gcp-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/gcp-method.hbs b/ui/app/templates/components/wizard/gcp-method.hbs
index 36869babcac9..625b7c957957 100644
--- a/ui/app/templates/components/wizard/gcp-method.hbs
+++ b/ui/app/templates/components/wizard/gcp-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/gcpkms-engine.hbs b/ui/app/templates/components/wizard/gcpkms-engine.hbs
index 18fc848198be..6004b65e703b 100644
--- a/ui/app/templates/components/wizard/gcpkms-engine.hbs
+++ b/ui/app/templates/components/wizard/gcpkms-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/kmip-engine.hbs b/ui/app/templates/components/wizard/kmip-engine.hbs
index aed2bc6a7b36..3c743c6f49f2 100644
--- a/ui/app/templates/components/wizard/kmip-engine.hbs
+++ b/ui/app/templates/components/wizard/kmip-engine.hbs
@@ -1,4 +1,4 @@
-
The KMIP secrets engine allows Vault to act as a KMIP server provider and handle the lifecycle of KMIP managed
diff --git a/ui/app/templates/components/wizard/kubernetes-method.hbs b/ui/app/templates/components/wizard/kubernetes-method.hbs
index fe39cec59478..2fa1cc349037 100644
--- a/ui/app/templates/components/wizard/kubernetes-method.hbs
+++ b/ui/app/templates/components/wizard/kubernetes-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/kv-engine.hbs b/ui/app/templates/components/wizard/kv-engine.hbs
index c03a8d17cbfe..ed73c82b8fd3 100644
--- a/ui/app/templates/components/wizard/kv-engine.hbs
+++ b/ui/app/templates/components/wizard/kv-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/ldap-method.hbs b/ui/app/templates/components/wizard/ldap-method.hbs
index 1855694d5f4c..356720b04ce5 100644
--- a/ui/app/templates/components/wizard/ldap-method.hbs
+++ b/ui/app/templates/components/wizard/ldap-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/okta-method.hbs b/ui/app/templates/components/wizard/okta-method.hbs
index 1440bebe5a55..b61ec473a26b 100644
--- a/ui/app/templates/components/wizard/okta-method.hbs
+++ b/ui/app/templates/components/wizard/okta-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/pki-engine.hbs b/ui/app/templates/components/wizard/pki-engine.hbs
index 73a9d21293c9..f847aa46ea52 100644
--- a/ui/app/templates/components/wizard/pki-engine.hbs
+++ b/ui/app/templates/components/wizard/pki-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/radius-method.hbs b/ui/app/templates/components/wizard/radius-method.hbs
index 6df40fab1885..cb0d5b9fff55 100644
--- a/ui/app/templates/components/wizard/radius-method.hbs
+++ b/ui/app/templates/components/wizard/radius-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/replication-setup.hbs b/ui/app/templates/components/wizard/replication-setup.hbs
index 449ac22b0b33..1e9b1944e5e9 100644
--- a/ui/app/templates/components/wizard/replication-setup.hbs
+++ b/ui/app/templates/components/wizard/replication-setup.hbs
@@ -10,11 +10,12 @@
- Learn: Setting Up Performance Replication
+
+ Learn: Setting Up Performance Replication
-
+
Learn: Setting up Disaster Recovery
diff --git a/ui/app/templates/components/wizard/secrets-display.hbs b/ui/app/templates/components/wizard/secrets-display.hbs
index fa895b5f57db..a907ca56ef68 100644
--- a/ui/app/templates/components/wizard/secrets-display.hbs
+++ b/ui/app/templates/components/wizard/secrets-display.hbs
@@ -26,11 +26,11 @@
>
{{#if @isSupported}}
- Create another {{unless @needsEncryption @mountName}} {{@nextStep}} {{if @needsEncryption "key"}}
+ Create another {{unless @needsEncryption @mountName}} {{@nextStep}} {{if @needsEncryption "key"}}
{{/if}}
- Enable another Secrets Engine
+ Enable another Secrets Engine
{{@nextFeature}}
diff --git a/ui/app/templates/components/wizard/ssh-engine.hbs b/ui/app/templates/components/wizard/ssh-engine.hbs
index b17e0a7b2a54..46d3b545b12e 100644
--- a/ui/app/templates/components/wizard/ssh-engine.hbs
+++ b/ui/app/templates/components/wizard/ssh-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/totp-engine.hbs b/ui/app/templates/components/wizard/totp-engine.hbs
index 46ccd0aa778a..9a2047cfe155 100644
--- a/ui/app/templates/components/wizard/totp-engine.hbs
+++ b/ui/app/templates/components/wizard/totp-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/transit-engine.hbs b/ui/app/templates/components/wizard/transit-engine.hbs
index 4bc593e8cbe1..ebb46bb86f01 100644
--- a/ui/app/templates/components/wizard/transit-engine.hbs
+++ b/ui/app/templates/components/wizard/transit-engine.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/components/wizard/tutorial-complete.hbs b/ui/app/templates/components/wizard/tutorial-complete.hbs
index fdc43af84efd..3170c85cc6c0 100644
--- a/ui/app/templates/components/wizard/tutorial-complete.hbs
+++ b/ui/app/templates/components/wizard/tutorial-complete.hbs
@@ -4,7 +4,7 @@
-
+
Close
diff --git a/ui/app/templates/components/wizard/tutorial-error.hbs b/ui/app/templates/components/wizard/tutorial-error.hbs
index 12291f863d85..fa5d1974b4d8 100644
--- a/ui/app/templates/components/wizard/tutorial-error.hbs
+++ b/ui/app/templates/components/wizard/tutorial-error.hbs
@@ -7,7 +7,7 @@
- Go Back
+ Go Back
{{@nextFeature}}
diff --git a/ui/app/templates/components/wizard/tutorial-idle.hbs b/ui/app/templates/components/wizard/tutorial-idle.hbs
index eb9a8e96315c..49a72575c71a 100644
--- a/ui/app/templates/components/wizard/tutorial-idle.hbs
+++ b/ui/app/templates/components/wizard/tutorial-idle.hbs
@@ -5,7 +5,7 @@
@hidePopup={{true}}
>
-
+
Want a tour? Our helpful guide will introduce you to the Vault Web UI.
diff --git a/ui/app/templates/components/wizard/tutorial-paused.hbs b/ui/app/templates/components/wizard/tutorial-paused.hbs
index b8f91238492e..1088b3f994a0 100644
--- a/ui/app/templates/components/wizard/tutorial-paused.hbs
+++ b/ui/app/templates/components/wizard/tutorial-paused.hbs
@@ -5,7 +5,7 @@
@hidePopup={{true}}
>
-
+
Feel free to explore Vault. Click below to get back to the guide or close this window.
diff --git a/ui/app/templates/components/wizard/userpass-method.hbs b/ui/app/templates/components/wizard/userpass-method.hbs
index df11cf5642f6..d10bc573a927 100644
--- a/ui/app/templates/components/wizard/userpass-method.hbs
+++ b/ui/app/templates/components/wizard/userpass-method.hbs
@@ -1,6 +1,6 @@
diff --git a/ui/app/templates/vault.hbs b/ui/app/templates/vault.hbs
index e9e36f17996e..f30203ba9f0b 100644
--- a/ui/app/templates/vault.hbs
+++ b/ui/app/templates/vault.hbs
@@ -3,10 +3,10 @@