Skip to content

Commit

Permalink
chore: rename api-token to api-path (#1830)
Browse files Browse the repository at this point in the history
## Description

We noticed users in the open source being confused about the rhetoric
around `api-token`. The `token` in this sense is a random path to get to
the endpoints for mutate/validate

## Related Issue

Fixes #1785 
<!-- or -->
Relates to #

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Other (security config, docs update, etc)

## Checklist before merging
- [x] Unit,
[Journey](https://github.com/defenseunicorns/pepr/tree/main/journey),
[E2E Tests](https://github.com/defenseunicorns/pepr-excellent-examples),
[docs](https://github.com/defenseunicorns/pepr/tree/main/docs),
[adr](https://github.com/defenseunicorns/pepr/tree/main/adr) added or
updated as needed
- [x] [Contributor Guide
Steps](https://docs.pepr.dev/main/contribute/#submitting-a-pull-request)
followed

---------

Signed-off-by: Case Wylie <[email protected]>
  • Loading branch information
cmwylie19 authored Feb 18, 2025
1 parent a444b81 commit bdf8d80
Show file tree
Hide file tree
Showing 19 changed files with 84 additions and 84 deletions.
10 changes: 5 additions & 5 deletions hack/soak.ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ metadata:
apiVersion: v1
kind: Secret
metadata:
name: pepr-soak-ci-api-token
name: pepr-soak-ci-api-path
namespace: pepr-system
type: Opaque
data:
Expand Down Expand Up @@ -143,8 +143,8 @@ spec:
- name: tls-certs
mountPath: /etc/certs
readOnly: true
- name: api-token
mountPath: /app/api-token
- name: api-path
mountPath: /app/api-path
readOnly: true
- name: module
mountPath: /app/load
Expand All @@ -153,9 +153,9 @@ spec:
- name: tls-certs
secret:
secretName: pepr-soak-ci-tls
- name: api-token
- name: api-path
secret:
secretName: pepr-soak-ci-api-token
secretName: pepr-soak-ci-api-path
- name: module
secret:
secretName: pepr-soak-ci-module
Expand Down
12 changes: 6 additions & 6 deletions integration/cli/build.configequality.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ describe("build", () => {
expect(serviceAccount).toBeDefined();
}

for (const secretApiToken of [
resource.select(peprResources, kind.Secret, `${peprUuid}-api-token`),
resource.select(helmResources, kind.Secret, `${peprUuid}-api-token`),
for (const secretApiPath of [
resource.select(peprResources, kind.Secret, `${peprUuid}-api-path`),
resource.select(helmResources, kind.Secret, `${peprUuid}-api-path`),
]) {
expect(secretApiToken).toBeDefined();
expect(secretApiPath).toBeDefined();
}

for (const secretTls of [
Expand All @@ -179,9 +179,9 @@ describe("build", () => {
).toBe(`${peprUuid}-tls`);
expect(
deployAdmission
.spec!.template!.spec!.volumes!.filter(vol => vol.name === "api-token")
.spec!.template!.spec!.volumes!.filter(vol => vol.name === "api-path")
.at(0)!.secret!.secretName,
).toBe(`${peprUuid}-api-token`);
).toBe(`${peprUuid}-api-path`);
expect(
deployAdmission
.spec!.template!.spec!.volumes!.filter(vol => vol.name === "module")
Expand Down
28 changes: 14 additions & 14 deletions journey/pepr-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ export function peprDev() {
await waitForServer();
});

it("should protect the controller mutate & validate endpoint with an API token", async () => {
await validateAPIKey();
it("should protect the controller mutate & validate endpoint with an API path", async () => {
await validateAPIPath();
});

it("should expose Prometheus metrics", async () => {
Expand Down Expand Up @@ -136,22 +136,22 @@ async function waitForServer() {
}
}

async function validateAPIKey() {
async function validateAPIPath() {
const mutateUrl = `${fetchBaseUrl}/mutate/`;
const validateUrl = `${fetchBaseUrl}/validate/`;
const fetchPushOpts = { ...fetchOpts, method: "POST" };

// Test for empty api token
const emptyMutateToken = await fetch(mutateUrl, fetchPushOpts);
expect(emptyMutateToken.status).toBe(404);
const emptyValidateToken = await fetch(validateUrl, fetchPushOpts);
expect(emptyValidateToken.status).toBe(404);

// Test api token validation
const evilMutateToken = await fetch(`${mutateUrl}evil-token`, fetchPushOpts);
expect(evilMutateToken.status).toBe(401);
const evilValidateToken = await fetch(`${validateUrl}evil-token`, fetchPushOpts);
expect(evilValidateToken.status).toBe(401);
// Test for empty api path
const emptyMutatePath = await fetch(mutateUrl, fetchPushOpts);
expect(emptyMutatePath.status).toBe(404);
const emptyValidatePath = await fetch(validateUrl, fetchPushOpts);
expect(emptyValidatePath.status).toBe(404);

// Test api path validation
const evilMutatePath = await fetch(`${mutateUrl}evil-path`, fetchPushOpts);
expect(evilMutatePath.status).toBe(401);
const evilValidatePath = await fetch(`${validateUrl}evil-path`, fetchPushOpts);
expect(evilValidatePath.status).toBe(401);
}

async function validateMetrics() {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export default function (program: RootCmd): void {
...process.env,
LOG_LEVEL: "debug",
PEPR_MODE: "dev",
PEPR_API_TOKEN: webhook.apiToken,
PEPR_API_PATH: webhook.apiPath,
PEPR_PRETTY_LOGS: "true",
SSL_KEY_PATH: "insecure-tls.key",
SSL_CERT_PATH: "insecure-tls.crt",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/assets/assets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ jest.mock("./index", () => ({
watcherServiceYaml: "/tmp/watcher-service.yaml",
admissionServiceYaml: "/tmp/admission-service.yaml",
tlsSecretYaml: "/tmp/tls-secret.yaml",
apiTokenSecretYaml: "/tmp/api-token-secret.yaml",
apiPathSecretYaml: "/tmp/api-path-secret.yaml",
storeRoleYaml: "/tmp/store-role.yaml",
storeRoleBindingYaml: "/tmp/store-role-binding.yaml",
clusterRoleYaml: "/tmp/cluster-role.yaml",
Expand Down
12 changes: 6 additions & 6 deletions src/lib/assets/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import { loadCapabilities } from "./loader";
import { namespaceComplianceValidator, dedent } from "../helpers";
import { promises as fs } from "fs";
import { storeRole, storeRoleBinding, clusterRoleBinding, serviceAccount } from "./rbac";
import { watcherService, service, tlsSecret, apiTokenSecret } from "./networking";
import { watcherService, service, tlsSecret, apiPathSecret } from "./networking";
import { WebhookType } from "../enums";

export class Assets {
readonly name: string;
readonly tls: TLSOut;
readonly apiToken: string;
readonly apiPath: string;
readonly config: ModuleConfig;
readonly path: string;
readonly alwaysIgnore!: WebhookIgnore;
Expand All @@ -53,8 +53,8 @@ export class Assets {
// Generate the ephemeral tls things
this.tls = genTLS(host || `${this.name}.pepr-system.svc`);

// Generate the api token for the controller / webhook
this.apiToken = crypto.randomBytes(32).toString("hex");
// Generate the api path for the controller / webhook
this.apiPath = crypto.randomBytes(32).toString("hex");
}

async deploy(
Expand Down Expand Up @@ -149,7 +149,7 @@ export class Assets {
[helm.files.watcherServiceYaml, (): string => toYaml(watcherService(this.name))],
[helm.files.admissionServiceYaml, (): string => toYaml(service(this.name))],
[helm.files.tlsSecretYaml, (): string => toYaml(tlsSecret(this.name, this.tls))],
[helm.files.apiTokenSecretYaml, (): string => toYaml(apiTokenSecret(this.name, this.apiToken))],
[helm.files.apiPathSecretYaml, (): string => toYaml(apiPathSecret(this.name, this.apiPath))],
[helm.files.storeRoleYaml, (): string => toYaml(storeRole(this.name))],
[helm.files.storeRoleBindingYaml, (): string => toYaml(storeRoleBinding(this.name))],
[helm.files.clusterRoleYaml, (): string => dedent(clusterRoleTemplate())],
Expand All @@ -164,7 +164,7 @@ export class Assets {
name: this.name,
image: this.image,
config: this.config,
apiToken: this.apiToken,
apiPath: this.apiPath,
capabilities: this.capabilities,
};
await overridesFile(overrideData, helm.files.valuesYaml, this.imagePullSecrets);
Expand Down
8 changes: 4 additions & 4 deletions src/lib/assets/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { V1PolicyRule as PolicyRule } from "@kubernetes/client-node";

import { Assets } from "./assets";
import Log from "../telemetry/logger";
import { apiTokenSecret, service, tlsSecret, watcherService } from "./networking";
import { apiPathSecret, service, tlsSecret, watcherService } from "./networking";
import { getDeployment, getModuleSecret, getNamespace, getWatcher } from "./pods";
import { clusterRole, clusterRoleBinding, serviceAccount, storeRole, storeRoleBinding } from "./rbac";
import { peprStoreCRD } from "./store";
Expand Down Expand Up @@ -136,9 +136,9 @@ async function setupController(assets: Assets, code: Buffer, hash: string, force
const tls = tlsSecret(name, assets.tls);
await K8s(kind.Secret).Apply(tls, { force });

Log.info("Applying API token secret");
const apiToken = apiTokenSecret(name, assets.apiToken);
await K8s(kind.Secret).Apply(apiToken, { force });
Log.info("Applying API path secret");
const apiPath = apiPathSecret(name, assets.apiPath);
await K8s(kind.Secret).Apply(apiPath, { force });

Log.info("Applying deployment");
const dep = getDeployment(assets, hash, assets.buildTimestamp);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/assets/destroy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function destroyModule(name: string): Promise<void> {
K8s(kind.Secret, { namespace }).Delete(`${name}-module`),
K8s(kind.Service, { namespace }).Delete(name),
K8s(kind.Secret, { namespace }).Delete(`${name}-tls`),
K8s(kind.Secret, { namespace }).Delete(`${name}-api-token`),
K8s(kind.Secret, { namespace }).Delete(`${name}-api-path`),
K8s(kind.Deployment, { namespace }).Delete(name),
K8s(kind.Deployment, { namespace }).Delete(`${name}-watcher`),
K8s(kind.Service, { namespace }).Delete(`${name}-watcher`),
Expand Down
8 changes: 4 additions & 4 deletions src/lib/assets/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ export function admissionDeployTemplate(buildTimestamp: string): string {
- name: tls-certs
mountPath: /etc/certs
readOnly: true
- name: api-token
mountPath: /app/api-token
- name: api-path
mountPath: /app/api-path
readOnly: true
- name: module
mountPath: /app/load
Expand All @@ -234,9 +234,9 @@ export function admissionDeployTemplate(buildTimestamp: string): string {
- name: tls-certs
secret:
secretName: {{ .Values.uuid }}-tls
- name: api-token
- name: api-path
secret:
secretName: {{ .Values.uuid }}-api-token
secretName: {{ .Values.uuid }}-api-path
- name: module
secret:
secretName: {{ .Values.uuid }}-module
Expand Down
2 changes: 1 addition & 1 deletion src/lib/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function helmLayout(basePath: string, unique: string): Record<string, Rec
watcherDeploymentYaml: `${helm.dirs.tmpls}/watcher-deployment.yaml`,
watcherServiceMonitorYaml: `${helm.dirs.tmpls}/watcher-service-monitor.yaml`,
tlsSecretYaml: `${helm.dirs.tmpls}/tls-secret.yaml`,
apiTokenSecretYaml: `${helm.dirs.tmpls}/api-token-secret.yaml`,
apiPathSecretYaml: `${helm.dirs.tmpls}/api-path-secret.yaml`,
moduleSecretYaml: `${helm.dirs.tmpls}/module-secret.yaml`,
storeRoleYaml: `${helm.dirs.tmpls}/store-role.yaml`,
storeRoleBindingYaml: `${helm.dirs.tmpls}/store-role-binding.yaml`,
Expand Down
6 changes: 3 additions & 3 deletions src/lib/assets/networking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { kind } from "kubernetes-fluent-client";

import { TLSOut } from "../tls";

export function apiTokenSecret(name: string, apiToken: string): kind.Secret {
export function apiPathSecret(name: string, apiPath: string): kind.Secret {
return {
apiVersion: "v1",
kind: "Secret",
metadata: {
name: `${name}-api-token`,
name: `${name}-api-path`,
namespace: "pepr-system",
},
type: "Opaque",
data: {
value: Buffer.from(apiToken).toString("base64"),
value: Buffer.from(apiPath).toString("base64"),
},
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/assets/pods.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const assets: Assets = JSON.parse(`{
"key": ""
}
},
"apiToken": "db5eb6d40e3744fcc2d7863c8f56ce24aaa94ff32cf22918700bdb9369e6d426",
"apiPath": "db5eb6d40e3744fcc2d7863c8f56ce24aaa94ff32cf22918700bdb9369e6d426",
"alwaysIgnore": {
"namespaces": []
},
Expand Down
8 changes: 4 additions & 4 deletions src/lib/assets/pods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@ export function getDeployment(
readOnly: true,
},
{
name: "api-token",
mountPath: "/app/api-token",
name: "api-path",
mountPath: "/app/api-path",
readOnly: true,
},
{
Expand All @@ -317,9 +317,9 @@ export function getDeployment(
},
},
{
name: "api-token",
name: "api-path",
secret: {
secretName: `${name}-api-token`,
secretName: `${name}-api-path`,
},
},
{
Expand Down
6 changes: 3 additions & 3 deletions src/lib/assets/webhooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const assets: Assets = JSON.parse(`{
"key": ""
}
},
"apiToken": "db5eb6d40e3744fcc2d7863c8f56ce24aaa94ff32cf22918700bdb9369e6d426",
"apiPath": "db5eb6d40e3744fcc2d7863c8f56ce24aaa94ff32cf22918700bdb9369e6d426",
"alwaysIgnore": {
"namespaces": []
},
Expand Down Expand Up @@ -322,8 +322,8 @@ describe("webhookConfigGenerator", () => {
it("should use a specified host", async () => {
const assetsWithHost = new Assets(assets.config, assets.path, assets.imagePullSecrets, "localhost");
assetsWithHost.capabilities = assets.capabilities;
const apiTokenPattern = "[a-fA-F0-9]{32}";
const expected = new RegExp(`https:\\/\\/localhost:3000\\/validate\\/${apiTokenPattern}`);
const apiPathPattern = "[a-fA-F0-9]{32}";
const expected = new RegExp(`https:\\/\\/localhost:3000\\/validate\\/${apiPathPattern}`);

const result = await webhookConfigGenerator(assetsWithHost, WebhookType.VALIDATE);

Expand Down
10 changes: 5 additions & 5 deletions src/lib/assets/webhooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export async function webhookConfigGenerator(
): Promise<kind.MutatingWebhookConfiguration | kind.ValidatingWebhookConfiguration | null> {
const ignore: V1LabelSelectorRequirement[] = [];

const { name, tls, config, apiToken, host } = assets;
const { name, tls, config, apiPath, host } = assets;
const ignoreNS = concat(peprIgnoreNamespaces, resolveIgnoreNamespaces(config?.alwaysIgnore?.namespaces));

// Add any namespaces to ignore
Expand All @@ -91,18 +91,18 @@ export async function webhookConfigGenerator(
caBundle: tls.ca,
};

// The URL must include the API Token
const apiPath = `/${mutateOrValidate}/${apiToken}`;
// The URL must include the API Path
const fullApiPath = `/${mutateOrValidate}/${apiPath}`;

// If a host is specified, use that with a port of 3000
if (host) {
clientConfig.url = `https://${host}:3000${apiPath}`;
clientConfig.url = `https://${host}:3000${fullApiPath}`;
} else {
// Otherwise, use the service
clientConfig.service = {
name: name,
namespace: "pepr-system",
path: apiPath,
path: fullApiPath,
};
}

Expand Down
6 changes: 3 additions & 3 deletions src/lib/assets/yaml/generateAllYaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import crypto from "crypto";
import { Assets } from "../assets";
import { WebhookType } from "../../enums";
import { apiTokenSecret, service, tlsSecret, watcherService } from "../networking";
import { apiPathSecret, service, tlsSecret, watcherService } from "../networking";
import { clusterRole, clusterRoleBinding, serviceAccount, storeRole, storeRoleBinding } from "../rbac";
import { dumpYaml, V1Deployment } from "@kubernetes/client-node";
import { getModuleSecret, getNamespace } from "../pods";
Expand All @@ -14,7 +14,7 @@ import { webhookConfigGenerator } from "../webhooks";
type deployments = { default: V1Deployment; watch: V1Deployment | null };

export async function generateAllYaml(assets: Assets, deployments: deployments): Promise<string> {
const { name, tls, apiToken, path, config } = assets;
const { name, tls, apiPath, path, config } = assets;
const code = await fs.readFile(path);
const hash = crypto.createHash("sha256").update(code).digest("hex");

Expand All @@ -23,7 +23,7 @@ export async function generateAllYaml(assets: Assets, deployments: deployments):
clusterRole(name, assets.capabilities, config.rbacMode, config.rbac),
clusterRoleBinding(name),
serviceAccount(name),
apiTokenSecret(name, apiToken),
apiPathSecret(name, apiPath),
tlsSecret(name, tls),
deployments.default,
service(name),
Expand Down
6 changes: 3 additions & 3 deletions src/lib/assets/yaml/overridesFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { clusterRole } from "../rbac";
import { promises as fs } from "fs";

type ChartOverrides = {
apiToken: string;
apiPath: string;
capabilities: CapabilityExport[];
config: ModuleConfig;
hash: string;
Expand All @@ -16,7 +16,7 @@ type ChartOverrides = {

// Helm Chart overrides file (values.yaml) generated from assets
export async function overridesFile(
{ hash, name, image, config, apiToken, capabilities }: ChartOverrides,
{ hash, name, image, config, apiPath, capabilities }: ChartOverrides,
path: string,
imagePullSecrets: string[],
): Promise<void> {
Expand All @@ -27,7 +27,7 @@ export async function overridesFile(
additionalIgnoredNamespaces: [],
rbac: rbacOverrides,
secrets: {
apiToken: Buffer.from(apiToken).toString("base64"),
apiPath: Buffer.from(apiPath).toString("base64"),
},
hash,
namespace: {
Expand Down
Loading

0 comments on commit bdf8d80

Please sign in to comment.