Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions k8s/helm-vault-values.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ server:
affinity:
ha:
enabled: true

injector:
enabled: true
16 changes: 16 additions & 0 deletions k8s/secret-challenge-vault-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ spec:
type: RollingUpdate
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/tls-skip-verify: 'true'
vault.hashicorp.com/agent-inject-status: "update"
vault.hashicorp.com/namespace: "default"
vault.hashicorp.com/log-level: debug
vault.hashicorp.com/agent-inject-secret-challenge46: "secret/data/secret-challenge"
vault.hashicorp.com/agent-inject-template-challenge46: |
{{ with secret "/secret/data/secret-challenge" }}
{{ range $k, $v := .Data.data }}
{{ printf "%s=%s" $k $v }}
{{ end }}
{{ end }}
vault.hashicorp.com/role: "secret-challenge"
labels:
app: secret-challenge
name: secret-challenge
Expand All @@ -28,6 +42,8 @@ spec:
fsGroup: 2000
runAsGroup: 2000
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
serviceAccountName: vault
containers:
- image: jeroenwillemsen/wrongsecrets:1.8.1-k8s-vault
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.owasp.wrongsecrets.challenges.kubernetes;

import com.google.common.base.Strings;
import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/** This challenge is about having a secrets injected via Vault template. */
@Component
public class Challenge46 extends FixedAnswerChallenge {

private final Vaultpassword vaultPassword;
private final String mockedAnswer;

public Challenge46(Vaultpassword vaultPassword, @Value("${vaultpassword}") String mockedAnswer) {
this.vaultPassword = vaultPassword;
this.mockedAnswer = mockedAnswer;
}

@Override
public String getAnswer() {
return vaultPassword != null && !Strings.isNullOrEmpty(vaultPassword.getPasssword())
? vaultPassword.getPasssword()
: mockedAnswer;
}
}
7 changes: 7 additions & 0 deletions src/main/resources/explanations/challenge46.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
=== Spring Vault Template Injection

Vault template injection via agent injection typically involves injecting a sidecar container,
known as the Vault Agent, alongside your main application container.
The Vault Agent is responsible for interacting with HashiCorp Vault to retrieve secrets and inject them into the application's runtime environment.

Can you find secret injected into application environment?
6 changes: 6 additions & 0 deletions src/main/resources/explanations/challenge46_hint.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
This challenge can be solved using the following steps:

1. Run 'kubectl get pods -A' and find secret-challenge-xxx pod name

2. Run 'kubectl exec secret-challenge-xxx -c secret-challenge -n default -- cat vault/secrets/challenge44'
to print injected secrets from vault
7 changes: 7 additions & 0 deletions src/main/resources/explanations/challenge46_reason.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*Why Vault Template Injection is not always a good idea?*

While Vault agent injection via templates can be a convenient way to manage secrets in certain scenarios,
there are situations where it might not be the best approach.

Templates might accidentally expose sensitive information in logs or temporary files.
If not properly configured, secrets could end up in places where they are accessible by unauthorized users or processes.
14 changes: 14 additions & 0 deletions src/main/resources/wrong-secrets-configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -710,3 +710,17 @@ configurations:
category: *doc
ctf:
enabled: true

- name: Challenge 46
short-name: "challenge-46"
sources:
- class-name: "org.owasp.wrongsecrets.challenges.kubernetes.Challenge46"
explanation: "explanations/challenge46.adoc"
hint: "explanations/challenge46_hint.adoc"
reason: "explanations/challenge46_reason.adoc"
environments: [*k8s_vault]
difficulty: *expert
category: *vault
ctf:
enabled: true
missing_environment: "explanations/missing_vault.adoc"
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ void shouldSpoilExercises() throws Exception {
@Test
void shouldNotShowDisabledChallengeAnywhere() throws Exception {
for (var challenge : challenges.getChallengeDefinitions()) {
var shortname = challenge.name().shortName();
if (shortname.contains("46")) {
continue;
}
mvc.perform(get("/challenge/%s".formatted(challenge.name().shortName())))
.andExpect(status().isOk())
.andExpect(content().string(not(containsString("This challenge has been disabled."))));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.owasp.wrongsecrets.challenges.kubernetes;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

public class Challenge46Test {

@Test
void spoilerShouldGiveAnswerWithVault() {
var vaultPassword = new Vaultpassword();
vaultPassword.setPassword("answer");
var challenge = new Challenge46(vaultPassword, "");
assertThat(challenge.spoiler().solution()).isNotEmpty();
assertThat(challenge.answerCorrect(challenge.spoiler().solution())).isTrue();
}

@Test
void spoilerShouldGiveAnswer() {
var vaultPassword = new Vaultpassword();
vaultPassword.setPassword("");
var challenge = new Challenge46(vaultPassword, "answer");
assertThat(challenge.spoiler().solution()).isEqualTo("answer");
assertThat(challenge.answerCorrect(challenge.spoiler().solution())).isTrue();
}

@Test
void incorrectAnswerShouldNotSolveChallenge() {
var vaultPassword = new Vaultpassword();
vaultPassword.setPassword("answer");
var challenge = new Challenge46(vaultPassword, "");
assertThat(challenge.answerCorrect("wrong answer")).isFalse();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ void shouldNotShowDisabledChallengeAnywhere() throws Exception {
if (shortname.contains("7")
|| shortname.contains("9")
|| shortname.contains("10")
|| shortname.contains("11")) {
|| shortname.contains("11")
|| shortname.contains("46")) {
continue;
}
mvc.perform(get("/challenge/%s".formatted(challenge.name().shortName())))
Expand All @@ -79,7 +80,8 @@ void shouldEnableK8sExercises() throws Exception {
.andExpect(content().string(not(containsString("challenge-6_disabled-link"))))
.andExpect(
content().string(containsString("challenge-7_disabled-link"))) // vault is not visible
.andExpect(content().string(not(containsString("challenge-33_disabled-link"))));
.andExpect(content().string(not(containsString("challenge-33_disabled-link"))))
.andExpect(content().string(containsString("challenge-46_disabled-link")));
}

@Test
Expand Down