Skip to content

Commit 84c38ad

Browse files
committed
Enable heimdall middleware and add a go program for automating the loading of mock project data via the POST project endpoint
Signed-off-by: Andres Tobon <andrest2455@gmail.com>
1 parent ac6d016 commit 84c38ad

File tree

9 files changed

+671
-10
lines changed

9 files changed

+671
-10
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
---
4+
apiVersion: traefik.io/v1alpha1
5+
kind: Middleware
6+
metadata:
7+
name: lfx-v2-project-service
8+
namespace: lfx
9+
spec:
10+
forwardAuth:
11+
address: "http://heimdall.lfx.svc.cluster.local:4456"
12+
authResponseHeaders:
13+
- Authorization

charts/lfx-v2-project-service/templates/ingressroute.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ spec:
1313
routes:
1414
- kind: Rule
1515
match: >-
16-
Host(`{{.Values.ingress.hostname}}`)
16+
Host(`{{.Values.ingress.hostname}}`) &&
17+
(Path(`/projects`) || PathPrefix(`/projects/`) || Path(`/livez`) || Path(`/readyz`))
1718
priority: 10
18-
# TODO: add heimdall middleware once it is working - currently it causes a 403
19-
# middlewares:
20-
# - name: heimdall
19+
middlewares:
20+
- name: heimdall
2121
services:
2222
- kind: Service
2323
name: lfx-v2-project-service

charts/lfx-v2-project-service/templates/ruleset.yaml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,21 @@ metadata:
88
namespace: lfx
99
spec:
1010
rules:
11-
- id: "rule:lfx:lfx-v2-project-service"
11+
- id: "rule:lfx:lfx-v2-project-service:health"
12+
match:
13+
methods:
14+
- GET
15+
routes:
16+
- path: /livez
17+
- path: /readyz
18+
execute:
19+
- authenticator: anonymous_authenticator
20+
- authorizer: allow_all
21+
- finalizer: create_jwt
22+
config:
23+
values:
24+
aud: lfx-v2-project-service
25+
- id: "rule:lfx:lfx-v2-project-service:projects"
1226
match:
1327
methods:
1428
- GET
@@ -19,10 +33,15 @@ spec:
1933
- path: /projects
2034
- path: /projects/:id
2135
execute:
22-
- authenticator: authelia
36+
#- authenticator: authelia
2337
- authenticator: anonymous_authenticator
24-
- contextualizer: authelia_userinfo
38+
#- contextualizer: authelia_userinfo
2539
- authorizer: allow_all
40+
# - authorizer: openfga_check
41+
# config:
42+
# values:
43+
# relation: manager
44+
# object: "project:111"
2645
- finalizer: create_jwt
2746
config:
2847
values:

charts/lfx-v2-project-service/values.yaml

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,120 @@ nats:
1010
# url is the URL of the NATS server
1111
url: nats://nats.lfx.svc.cluster.local:4222
1212
projects_kv_bucket_name: projects
13+
14+
# heimdall is the configuration for the heimdall middleware
15+
heimdall:
16+
env:
17+
CLIENT_SECRET:
18+
secretKeyRef:
19+
name: heimdall-secrets
20+
key: heimdall_client_secret
21+
22+
mechanisms:
23+
authenticators:
24+
- id: anonymous_authenticator
25+
type: anonymous
26+
config:
27+
subject: "_anonymous"
28+
- id: authelia
29+
type: oauth2_introspection
30+
config:
31+
metadata_endpoint:
32+
url: http://auth.k8s.orb.local/.well-known/oauth-authorization-server
33+
resolved_endpoints:
34+
introspection_endpoint:
35+
auth:
36+
type: basic_auth
37+
config:
38+
user: heimdall
39+
password: ${CLIENT_SECRET}
40+
assertions:
41+
audience:
42+
- "http://lfx-api.k8s.orb.local/"
43+
subject:
44+
# Authelia doesn't provide a "sub" claim for client_credentials token
45+
# introspection. Use a GJSON query to extract either the username or
46+
# the client_id. Client IDs can collide with usernames (and GJSON
47+
# doesn't let us do array concatenation to add a literal prefix), so
48+
# the `sub` claim should NOT be used downstream.
49+
id: '[username,client_id].0'
50+
contextualizers:
51+
- id: authelia_userinfo
52+
type: generic
53+
config:
54+
endpoint:
55+
url: http://auth.k8s.orb.local/api/oidc/userinfo
56+
method: GET
57+
forward_headers:
58+
- Authorization
59+
# Continuing on error is needed if this contextualizer is used in any
60+
# rulesets that support anonymous access.
61+
continue_pipeline_on_error: true
62+
authorizers:
63+
- id: allow_all
64+
type: allow
65+
- id: deny_all
66+
type: deny
67+
- id: openfga_check
68+
type: remote
69+
config:
70+
endpoint: ${FGA_CHECK_ENDPOINT}
71+
values:
72+
# Most of the `values` are provided by the matching rule, but the
73+
# `model_id` needs to be set by an environment variable.
74+
model_id: ${FGA_MODEL_ID}
75+
payload: |
76+
{
77+
"authorization_model_id": "{{ .Values.model_id }}",
78+
"tuple_key": {
79+
"user": {{
80+
list
81+
"user:"
82+
(
83+
eq .Subject.ID "_anonymous"
84+
| ternary
85+
"_anonymous"
86+
(or
87+
.Subject.Attributes.username
88+
(list "clients@" .Subject.Attributes.client_id | join ""))
89+
)
90+
| join "" | quote
91+
}},
92+
"relation": "{{ .Values.relation }}",
93+
"object": "{{ .Values.object }}"
94+
}
95+
}
96+
expressions:
97+
- expression: |
98+
Payload.allowed == true
99+
finalizers:
100+
- id: create_jwt
101+
type: jwt
102+
config:
103+
signer:
104+
key_store:
105+
path: /secrets/signer.pem
106+
claims: |
107+
{
108+
"principal": {{
109+
eq .Subject.ID "_anonymous"
110+
| ternary
111+
"_anonymous"
112+
(or
113+
.Subject.Attributes.username
114+
(list "clients@" .Subject.Attributes.client_id | join ""))
115+
| quote
116+
}}
117+
{{ if .Outputs.authelia_userinfo.email -}},
118+
"email": {{ quote .Outputs.authelia_userinfo.email }}
119+
{{ end -}}
120+
{{ if .Values.aud -}},
121+
"aud": {{ quote .Values.aud }}
122+
{{ end -}}
123+
}
124+
125+
default_rule:
126+
execute:
127+
- authenticator: anonymous_authenticator
128+
- authorizer: deny_all
129+
- finalizer: create_jwt

cmd/project-api/jwt.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const (
2020
// PS256 is the default for Heimdall's JWT finalizer.
2121
signatureAlgorithm = validator.PS256
2222
defaultIssuer = "heimdall"
23-
defaultAudience = "query-svc"
23+
defaultAudience = "lfx-v2-project-service"
2424
)
2525

2626
var (
@@ -107,7 +107,7 @@ func (j *jwtAuth) parsePrincipal(ctx context.Context, token string, logger *slog
107107
// dropping the suffix of the 3rd error's String() method could be more
108108
// accurate to error boundaries, but could also expose tertiary errors if
109109
// errors are not wrapped with Go 1.13 `%w` semantics.
110-
logger.With(errKey, err).WarnContext(ctx, "authorization failed")
110+
logger.With("default_audience", defaultAudience).With("default_issuer", defaultIssuer).With(errKey, err).WarnContext(ctx, "authorization failed")
111111
errString := err.Error()
112112
firstColon := strings.Index(errString, ":")
113113
if firstColon != -1 && firstColon+1 < len(errString) {

cmd/project-api/service_endpoint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,8 @@ func (s *ProjectsService) Livez(_ context.Context) ([]byte, error) {
528528
// JWTAuth implements Auther interface for the JWT security scheme.
529529
func (s *ProjectsService) JWTAuth(ctx context.Context, bearerToken string, _ *security.JWTScheme) (context.Context, error) {
530530
// Parse the Heimdall-authorized principal from the token.
531-
// TODO: handle error
532531
principal, _ := s.auth.parsePrincipal(ctx, bearerToken, s.logger)
532+
// TODO: handle error
533533
// if err != nil {
534534
// return ctx, err
535535
// }

tools/load_mock_data/Makefile

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
4+
# Makefile for Project Mock Data Loader
5+
6+
.PHONY: build run clean help test
7+
8+
# Default target
9+
help:
10+
@echo "Available targets:"
11+
@echo " build - Build the mock data loader binary"
12+
@echo " run - Run the mock data loader (requires -bearer-token)"
13+
@echo " clean - Remove build artifacts"
14+
@echo " test - Run tests (if any)"
15+
@echo ""
16+
@echo "Usage examples:"
17+
@echo " make build"
18+
@echo " make run ARGS='-bearer-token \"your-token\" -num-projects 5'"
19+
@echo " make run ARGS='-bearer-token \"your-token\" -api-url \"http://localhost:8080/projects\"'"
20+
21+
# Build the binary
22+
build:
23+
@echo "Building mock data loader..."
24+
go build -o bin/load_mock_data main.go
25+
@echo "Binary created: bin/load_mock_data"
26+
27+
# Run the script
28+
run:
29+
@if [ -z "$(ARGS)" ]; then \
30+
echo "Error: ARGS variable is required for run target"; \
31+
echo "Example: make run ARGS='-bearer-token \"your-token\" -num-projects 5'"; \
32+
exit 1; \
33+
fi
34+
@if [ ! -f "./bin/load_mock_data" ]; then \
35+
echo "Binary not found. Building first..."; \
36+
make build; \
37+
fi
38+
@echo "Running mock data loader with args: $(ARGS)"
39+
./bin/load_mock_data $(ARGS)
40+
41+
# Clean build artifacts
42+
clean:
43+
@echo "Cleaning build artifacts..."
44+
rm -f bin/load_mock_data
45+
@echo "Clean complete"
46+
47+
# Run tests (placeholder for future tests)
48+
test:
49+
@echo "Running tests..."
50+
@echo "No tests implemented yet"
51+
@echo "Tests complete"
52+
53+
# Install dependencies (if needed)
54+
deps:
55+
@echo "Installing dependencies..."
56+
go mod tidy
57+
@echo "Dependencies installed"
58+
59+
# Development mode - build and run with common args
60+
dev:
61+
@echo "Development mode - building and running with sample args..."
62+
make build
63+
@echo "To run with your token:"
64+
@echo " ./bin/load_mock_data -bearer-token \"your-jwt-token\" -num-projects 5"

0 commit comments

Comments
 (0)