Skip to content

Commit

Permalink
Merge pull request #1147 from OWASP/feature-vault-challenge
Browse files Browse the repository at this point in the history
  • Loading branch information
commjoen authored Jan 16, 2024
2 parents 7a31ff5 + 71a4c95 commit 6d96e1a
Show file tree
Hide file tree
Showing 20 changed files with 457 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/scripts/.bash_history
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ rm -rf jdk-18_linux-x64_bin.deb
git rebase -i main
git rebase -i master
git stash
export tempPassword="XvAn9Kcj4XKXBFfkL0IBttcYp8GmZq7JuPjIjghfDZw="
export tempPassword="T/8yzIOE0Xz3RIxjA2HMyncgmhUoZsHZLW6lQVj5yV4="
mvn run tempPassword
k6
npx k6
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,9 @@ If you want to dev without a Vault instance, use additionally the `without-vault
./mvnw spring-boot:run -Dspring-boot.run.profiles=local,without-vault
```

Want to push a container? See `.github/scripts/docker-create-and-push.sh` for a script that generates and pushes all containers. Do not forget to rebuild the app before composing the container
Want to push a container? See `.github/scripts/docker-create-and-push.sh` for a script that generates and pushes all containers. Do not forget to rebuild the app before composing the container.

Want to check why something in vault is not working in kubernetes? Do `kubectl exec vault-0 -n vault -- vault audit enable file file_path=stdout`.

### Dependency management

Expand Down
44 changes: 42 additions & 2 deletions k8s-vault-minkube-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ else
helm repo add hashicorp https://helm.releases.hashicorp.com
fi
kubectl create ns vault
helm upgrade --install vault hashicorp/vault --version 0.23.0 --namespace vault --values k8s/helm-vault-values.yml
helm upgrade --install vault hashicorp/vault --version 0.27.0 --namespace vault --values k8s/helm-vault-values.yml

isvaultrunning=$(kubectl get pods -n vault --field-selector=status.phase=Running)
while [[ $isvaultrunning != *"vault-0"* ]]; do echo "waiting for Vault1" && sleep 2 && isvaultrunning=$(kubectl get pods -n vault --field-selector=status.phase=Running); done
Expand Down Expand Up @@ -81,26 +81,66 @@ kubectl exec vault-0 -n vault -- vault secrets enable -path=secret kv-v2
echo "Putting a secret in"
kubectl exec vault-0 -n vault -- vault kv put secret/secret-challenge vaultpassword.password="$(openssl rand -base64 16)"

echo "Putting a subkey issue in"
kubectl exec vault-0 -n vault -- vault kv put secret/wrongsecret aaaauser."$(openssl rand -base64 8)"="$(openssl rand -base64 16)"

echo "Oepsi metadata"
kubectl exec vault-0 -n vault -- vault kv metadata put -mount=secret -custom-metadata=secret="$(openssl rand -base64 16)" wrongsecret

echo "Enable k8s auth"
kubectl exec vault-0 -n vault -- vault auth enable kubernetes

echo "Writing k8s auth config"

kubectl exec vault-0 -n vault -- /bin/sh -c 'vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt'

kubectl exec vault-0 -n vault -- vault audit enable file file_path=stdout

echo "Writing policy for secret-challenge"
kubectl exec vault-0 -n vault -- /bin/sh -c 'vault policy write secret-challenge - <<EOF
path "secret/data/secret-challenge" {
capabilities = ["read"]
}
path "secret/metadata/wrongsecret" {
capabilities = ["read", "list" ]
}
path "secret/subkeys/wrongsecret" {
capabilities = ["read", "list" ]
}
path "secret/data/wrongsecret" {
capabilities = ["read", "list" ]
}
path "secret/data/application" {
capabilities = ["read"]
}
EOF'

kubectl exec vault-0 -n vault -- /bin/sh -c 'vault policy write standard_sre - <<EOF
path "secret/data/secret-challenge" {
capabilities = ["list"]
}
path "secret/" {
capabilities = ["list"]
}
path "secret/*" {
capabilities = ["list"]
}
path "secret/*/subkeys/"{
capabilities = ["list", "read"]
}
path "secret/*/subkeys/*"{
capabilities = ["list", "read"]
}
path "secret/metadata/*"{
capabilities = ["list", "read"]
}
EOF'

kubectl exec vault-0 -n vault -- vault auth enable userpass
kubectl exec vault-0 -n vault -- vault write auth/userpass/users/helper password=foo policies=standard_sre

echo "Write secrets for secret-challenge"
kubectl exec vault-0 -n vault -- vault write auth/kubernetes/role/secret-challenge \
bound_service_account_names=vault \
Expand Down
2 changes: 1 addition & 1 deletion k8s/secret-challenge-vault-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ spec:
runAsNonRoot: true
serviceAccountName: vault
containers:
- image: jeroenwillemsen/wrongsecrets:1.8.1-k8s-vault
- image: jeroenwillemsen/wrongsecrets:challenge45-7-k8s-vault
imagePullPolicy: IfNotPresent
name: secret-challenge
securityContext:
Expand Down
30 changes: 25 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
</dependency>

<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-dependencies</artifactId>
Expand Down Expand Up @@ -123,11 +129,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
Expand All @@ -148,6 +149,20 @@
<version>${spring-security.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>vault</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand Down Expand Up @@ -278,6 +293,11 @@
<version>1.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>

<build>
Expand Down
42 changes: 40 additions & 2 deletions scripts/install-vault.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if [ $? == 0 ]; then
echo "Vault ns is already there"
else
kubectl create ns vault
helm upgrade --install vault hashicorp/vault --version 0.23.0 --namespace vault --values ../k8s/helm-vault-values.yml
helm upgrade --install vault hashicorp/vault --version 0.27.0 --namespace vault --values ../k8s/helm-vault-values.yml
fi


Expand Down Expand Up @@ -49,11 +49,16 @@ kubectl exec vault-0 -n vault -- vault secrets enable -path=secret kv-v2
echo "Putting a secret in"
kubectl exec vault-0 -n vault -- vault kv put secret/secret-challenge vaultpassword.password="$(openssl rand -base64 16)"

echo "Putting a subkey issue in"
kubectl exec vault-0 -n vault -- vault kv put secret/wrongsecret aaaauser."$(openssl rand -base64 8)"="$(openssl rand -base64 16)"

echo "Oepsi metadata"
kubectl exec vault-0 -n vault -- vault kv metadata put -mount=secret -custom-metadata=secret="$(openssl rand -base64 16)" wrongsecret

echo "Enable k8s auth"
kubectl exec vault-0 -n vault -- vault auth enable kubernetes

echo "Writing k8s auth config"

kubectl exec vault-0 -n vault -- /bin/sh -c 'vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
Expand All @@ -64,11 +69,44 @@ kubectl exec vault-0 -n vault -- /bin/sh -c 'vault policy write secret-challenge
path "secret/data/secret-challenge" {
capabilities = ["read"]
}
path "secret/metadata/wrongsecret" {
capabilities = ["read", "list" ]
}
path "secret/subkeys/wrongsecret" {
capabilities = ["read", "list" ]
}
path "secret/data/wrongsecret" {
capabilities = ["read", "list" ]
}
path "secret/data/application" {
capabilities = ["read"]
}
EOF'

kubectl exec vault-0 -n vault -- /bin/sh -c 'vault policy write standard_sre - <<EOF
path "secret/data/secret-challenge" {
capabilities = ["list"]
}
path "secret/" {
capabilities = ["list"]
}
path "secret/*" {
capabilities = ["list"]
}
path "secret/*/subkeys/"{
capabilities = ["list", "read"]
}
path "secret/*/subkeys/*"{
capabilities = ["list", "read"]
}
path "secret/metadata/*"{
capabilities = ["list", "read"]
}
EOF'

kubectl exec vault-0 -n vault -- vault auth enable userpass
kubectl exec vault-0 -n vault -- vault write auth/userpass/users/helper password=foo policies=standard_sre

echo "Write secrets for secret-challenge"
kubectl exec vault-0 -n vault -- vault write auth/kubernetes/role/secret-challenge \
bound_service_account_names=vault \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.owasp.wrongsecrets.challenges.kubernetes;

import com.google.common.base.Strings;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.vault.config.VaultProperties;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.vault.core.*;
import org.springframework.vault.support.Versioned;

/**
* This challenge is about having a metadata of secrets stored in a misconfigured Hashicorp Vault.
*/
@Component
@Slf4j
public class MetaDataChallenge extends FixedAnswerChallenge {

private final String vaultPasswordString;
private final VaultTemplate vaultTemplate;

private final VaultProperties.AuthenticationMethod authenticationMethod;

public MetaDataChallenge(
@Value("${vaultpassword}") String vaultPasswordString,
@Nullable VaultTemplate vaultTemplate,
@Value("${spring.cloud.vault.authentication}")
VaultProperties.AuthenticationMethod vaultAuthmethod) {
this.vaultPasswordString = vaultPasswordString;
this.vaultTemplate = vaultTemplate;
this.authenticationMethod = vaultAuthmethod;
}

public String getAnswer() {
try {
if (VaultProperties.AuthenticationMethod.NONE.equals(authenticationMethod)
|| vaultTemplate == null) {
log.warn("Vault not setup for challenge 44");
return vaultPasswordString;
}
VaultVersionedKeyValueOperations versionedOperations =
vaultTemplate.opsForVersionedKeyValue("secret");
Versioned<Map<String, Object>> versioned = versionedOperations.get("wrongsecret");
if (versioned == null) {
return vaultPasswordString;
}
var metadata = versioned.getMetadata();
if (metadata == null) {
return vaultPasswordString;
}
var customMetadata = metadata.getCustomMetadata();
if (!customMetadata.isEmpty()) {
String customMedataSecret = customMetadata.get("secret");
if (Strings.isNullOrEmpty(customMedataSecret)) {
return vaultPasswordString;
}
return customMedataSecret;
}
} catch (Exception e) {
log.warn("Exception during execution of challenge44", e);
}
return vaultPasswordString;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.owasp.wrongsecrets.challenges.kubernetes;

import java.util.Map;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.vault.config.VaultProperties;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.core.VaultVersionedKeyValueOperations;
import org.springframework.vault.support.Versioned;

@Component
@Slf4j
public class VaultSubKeyChallenge extends FixedAnswerChallenge {

private final String vaultPasswordString;
private final VaultTemplate vaultTemplate;

private final VaultProperties.AuthenticationMethod authenticationMethod;

public VaultSubKeyChallenge(
@Value("${vaultpassword}") String vaultPasswordString,
@Nullable VaultTemplate vaultTemplate,
@Value("${spring.cloud.vault.authentication}")
VaultProperties.AuthenticationMethod vaultAuthmethod) {
this.vaultPasswordString = vaultPasswordString;
this.vaultTemplate = vaultTemplate;
this.authenticationMethod = vaultAuthmethod;
}

@Override
public String getAnswer() {
try {
if (VaultProperties.AuthenticationMethod.NONE.equals(authenticationMethod)
|| vaultTemplate == null) {
log.warn("Vault not setup for challenge 45");
return vaultPasswordString;
}
VaultVersionedKeyValueOperations versionedOperations =
vaultTemplate.opsForVersionedKeyValue("secret");
Versioned<Map<String, Object>> versioned = versionedOperations.get("wrongsecret");
if (versioned == null) {
return vaultPasswordString;
}
Optional<String> first = versioned.getRequiredData().keySet().stream().findFirst();
return first.orElse(vaultPasswordString);

} catch (Exception e) {
log.warn("Exception during execution of challenge45", e);
}
return vaultPasswordString;
}
}
6 changes: 6 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ CHALLENGE33=if_you_see_this_please_use_k8s
ARG_BASED_PASSWORD=if_you_see_this_please_use_docker_instead
DOCKER_ENV_PASSWORD=if_you_see_this_please_use_docker_instead
vaultpassword=if_you_see_this_please_use_K8S_and_Vault
spring.cloud.vault.uri=https://tobediefined.org
spring.cloud.vault.authentication=NONE
spring.cloud.vault.role=none
spring.cloud.vault.kubernetes-path=none
spring.cloud.vault.scheme=https://tobediefined.org
spring.cloud.vault.kubernetes.service-account-token-file="none"
default_aws_value=if_you_see_this_please_use_AWS_Setup
default_aws_value_challenge_9=if_you_see_this_please_use_AWS_Setup
default_aws_value_challenge_10=if_you_see_this_please_use_AWS_Setup
Expand Down
9 changes: 9 additions & 0 deletions src/main/resources/explanations/challenge44.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== Vault Metadata Challenge

Secrets management systems now often have metadata support for their secrets! This is awesome, as it allows you to enrich the secret with contextual data further, making it easier to remember the secret.

But what if you put confidential/secret information into a secret by mistake?

A developer has put secret metadata on a `wrongsecret` in Vault. Can you find it?

Tip: take a look at the policies when vault is installed; you can see that the application is only allowed to use the metadata ;-).
Loading

0 comments on commit 6d96e1a

Please sign in to comment.