Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

Argus is a Go microservice for centralized, tamper-evident audit logging. It exposes a REST API and a
reusable client library (`pkg/audit`) that other Go services import to emit audit events. It's designed
to be the audit source of truth for the OpenNSW microservice platform.
to be the audit source of truth for any microservice platform.

## Commands

Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ audit.LogAuditEvent(ctx, &audit.AuditLogRequest{

---

## Integration with External Applications (e.g., OpenNSW)
## Integration with External Applications

Argus is designed to be the centralized audit source of truth for microservice platforms like [OpenNSW](https://github.com/OpenNSW/nsw/). By integrating the Argus client, your application gains high-performance, tamper-evident logging with zero impact on core performance.
Argus is designed to be the centralized audit source of truth for any microservice platform. By integrating the Argus client, your application gains high-performance, tamper-evident logging with zero impact on core performance.

### 1. Installation
In your application (e.g., `nsw-api` or `nsw-backend`):
In your application:
```bash
go get github.com/LSFLK/argus/pkg/audit
```
Expand All @@ -79,7 +79,7 @@ Initialize the client in your main entry point. For high-scale systems, tune the
func main() {
// Connect to the centralized Argus service deployed via GitOps
client := audit.NewClient(audit.Config{
BaseURL: "http://argus-service.nsw.svc.cluster.local:3001",
BaseURL: "http://argus-service.<your-namespace>.svc.cluster.local:3001",
BatchSize: 100,
BatchInterval: 500 * time.Millisecond,
WorkerCount: 10,
Expand All @@ -94,7 +94,7 @@ func main() {
To ensure logs cannot be spoofed, your application can sign requests using a private key. Argus will verify these on the server-side.

```go
// Example: Signing a log in an NSW Submission handler
// Example: Signing a log in a request handler
func HandleSubmission(ctx context.Context, sub *Submission) {
msgBytes, _ := json.Marshal(map[string]interface{}{"submission_id": sub.ID})
req := &audit.AuditLogRequest{
Expand All @@ -106,16 +106,16 @@ func HandleSubmission(ctx context.Context, sub *Submission) {

// Attach signature using your service's private key
// req.Signature = sign(req, myPrivateKey)
// req.PublicKeyID = "nsw-api-prod-01"
// req.PublicKeyID = "my-service-prod-01"

audit.LogAuditEvent(ctx, req)
}
```

### 4. Benefits for National-Scale Platforms
- **Centralized Compliance:** Single point of audit for multiple agencies and microservices (e.g., FCAU, IRD, NPQS).
### 4. Benefits for Large-Scale Platforms
- **Centralized Compliance:** Single point of audit for multiple teams, agencies, or microservices.
- **WORM Storage Ready:** Using the Pipeline architecture, you can route logs to S3 Object Lock or physical WORM drives for regulatory compliance.
- **Traceability:** Propagate `trace_id` from Argus into your downstream logs for end-to-end observability across Temporal workflows and APIs.
- **Traceability:** Propagate `trace_id` from Argus into your downstream logs for end-to-end observability across distributed workflows and APIs.

---

Expand Down Expand Up @@ -153,15 +153,15 @@ Argus provides an official Helm chart published as an **OCI Artifact** to GitHub
```bash
helm upgrade --install argus oci://ghcr.io/lsflk/charts/argus \
--version 0.1.0 \
-n nsw-infra-staging \
-n <your-namespace> \
--create-namespace \
-f custom-values.yaml
```

### Standalone Deployment from Source
```bash
helm upgrade --install argus ./deployments/helm/argus \
-n nsw-infra-staging \
-n <your-namespace> \
--create-namespace \
-f ./deployments/helm/argus/values.yaml
```
Expand Down
20 changes: 10 additions & 10 deletions deployments/helm/argus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Argus Helm charts are published as OCI artifacts to the GitHub Container Registr
# Install directly from OCI registry
helm upgrade --install argus oci://ghcr.io/lsflk/charts/argus \
--version 0.1.0 \
--namespace nsw-infra-staging \
--namespace <your-namespace> \
--create-namespace \
--values ./custom-values.yaml
```
Expand All @@ -45,7 +45,7 @@ To deploy Argus from the local repository directory:

```bash
helm upgrade --install argus ./deployments/helm/argus \
--namespace nsw-infra-staging \
--namespace <your-namespace> \
--create-namespace \
--values ./deployments/helm/argus/values.yaml
```
Expand All @@ -67,11 +67,11 @@ In your environment values file (e.g., `envs/staging/infra-values.yaml`):
argus:
enabled: true
auth:
existingSecret: "nsw-db-credentials"
existingSecret: "argus-db-credentials"
env:
DB_HOST: "staging-nsw-db"
DB_NAME: "nsw_staging"
S3_COMPLIANCE_BUCKET: "nsw-audit-compliance-logs-staging"
DB_HOST: "staging-db"
DB_NAME: "argus_staging"
S3_COMPLIANCE_BUCKET: "audit-compliance-logs-staging"
```

---
Expand All @@ -80,7 +80,7 @@ argus:

### Automated (CI/CD)

The Helm chart automation mirrors the `nsw-srilanka` and `nsw-agency` setup:
The Helm chart automation follows a standard GitOps setup:
- **Dev Chart (`.github/workflows/build-dev-chart.yml`)**: On pushes to `main` with chart changes (or manual dispatch), packages and publishes a dev chart (`0.0.0-dev.<run_number>`) to `oci://ghcr.io/lsflk/charts`.
- **Chart CI (`.github/workflows/helm-ci.yml`)**: Lints the chart and verifies template rendering on pull requests.

Expand All @@ -106,16 +106,16 @@ helm push .cr-release-packages/argus-0.1.0.tgz oci://ghcr.io/lsflk/charts
| Parameter | Description | Default |
| --- | --- | --- |
| `replicaCount` | Number of pod replicas | `2` |
| `image.repository` | Container image repository | `ghcr.io/opennsw/argus` |
| `image.repository` | Container image repository | `ghcr.io/lsflk/argus` |
| `image.tag` | Container image tag | `f21da85558410c19b6a96275b6e0eef2a788fb4b` |
| `service.type` | Kubernetes service type | `ClusterIP` |
| `service.port` | Service port | `3001` |
| `env.ENVIRONMENT` | Deployment environment | `production` |
| `env.DB_TYPE` | Database driver (`postgres` or `sqlite`) | `postgres` |
| `env.DB_HOST` | Database host | `nsw-db` |
| `env.DB_HOST` | Database host | `audit-db` |
| `env.DB_PORT` | Database port | `5432` |
| `env.DB_NAME` | Database name | `audit_db` |
| `env.REQUIRE_SIGNATURES` | Enable signature verification | `"true"` |
| `env.S3_COMPLIANCE_BUCKET` | S3 WORM compliance bucket name | `"nsw-audit-compliance-logs-staging"` |
| `env.S3_COMPLIANCE_BUCKET` | S3 WORM compliance bucket name | `"audit-compliance-logs-staging"` |
| `auth.existingSecret` | Existing Kubernetes secret containing `DB_PASSWORD` | `""` |
| `auth.externalSecrets.enabled` | Enable ExternalSecrets Operator (ESO) | `false` |
14 changes: 7 additions & 7 deletions deployments/helm/argus/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
replicaCount: 2

image:
repository: ghcr.io/opennsw/argus
repository: ghcr.io/lsflk/argus
tag: f21da85558410c19b6a96275b6e0eef2a788fb4b
pullPolicy: IfNotPresent

Expand All @@ -30,15 +30,15 @@ securityContext:
env:
ENVIRONMENT: production
DB_TYPE: postgres
DB_HOST: nsw-db
DB_HOST: audit-db
DB_PORT: 5432
DB_NAME: audit_db
DB_SSLMODE: disable
REQUIRE_SIGNATURES: "true"
AUDIT_ENUMS_CONFIG: "/app/configs/enums.yaml"

# AWS S3 Compliance Settings (Object Lock)
S3_COMPLIANCE_BUCKET: "nsw-audit-compliance-logs-staging"
S3_COMPLIANCE_BUCKET: "audit-compliance-logs-staging"
S3_REGION: "us-east-1"
S3_PREFIX: "audit-logs"
S3_RETENTION_DAYS: "2555"
Expand All @@ -56,10 +56,10 @@ auth:
# Enables Vault integration for injecting secrets securely
externalSecrets:
enabled: false
secretStoreName: "nsw-vault-backend"
secretStoreName: "vault-backend"
secretStoreKind: "ClusterSecretStore"
refreshInterval: "1h"
# Vault key containing DB credentials
remoteDbKey: "nsw/staging/db"
remoteDbKey: "argus/staging/db"
# Vault key containing AWS S3 access/secret keys
remoteAwsKey: "nsw/staging/aws"
remoteAwsKey: "argus/staging/aws"
14 changes: 7 additions & 7 deletions deployments/helm/values-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
replicaCount: 2

image:
repository: ghcr.io/opennsw/argus
repository: ghcr.io/lsflk/argus
tag: "1.0.0"
pullPolicy: IfNotPresent

Expand All @@ -30,15 +30,15 @@ securityContext:
env:
ENVIRONMENT: production
DB_TYPE: postgres
DB_HOST: nsw-db
DB_HOST: audit-db
DB_PORT: 5432
DB_NAME: audit_db
DB_SSLMODE: disable
REQUIRE_SIGNATURES: "true"
AUDIT_ENUMS_CONFIG: "/app/configs/enums.yaml"

# AWS S3 Compliance Settings (Object Lock)
S3_COMPLIANCE_BUCKET: "nsw-audit-compliance-logs-staging"
S3_COMPLIANCE_BUCKET: "audit-compliance-logs-staging"
S3_REGION: "us-east-1"
S3_PREFIX: "audit-logs"
S3_RETENTION_DAYS: "2555"
Expand All @@ -52,8 +52,8 @@ auth:
existingSecret: ""
externalSecrets:
enabled: false
secretStoreName: "nsw-vault-backend"
secretStoreName: "vault-backend"
secretStoreKind: "ClusterSecretStore"
refreshInterval: "1h"
remoteDbKey: "nsw/staging/db"
remoteAwsKey: "nsw/staging/aws"
remoteDbKey: "argus/staging/db"
remoteAwsKey: "argus/staging/aws"
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ curl -X POST http://localhost:3001/api/audit-logs \
"metadata": {"schemaId": "schema-123", "decision": "ALLOWED"},
"signature": "base64-encoded-signature",
"signatureAlgorithm": "RS256",
"publicKeyId": "nsw-key-1"
"publicKeyId": "my-key-1"
}'
```

Expand Down
2 changes: 1 addition & 1 deletion pkg/audit/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type AuditLogRequest struct {
TargetID *string `json:"targetId,omitempty"` // resource_id or service_name

// Payload & Metadata
Message []byte `json:"message"` // Specific blob for NSW/NPQS
Message []byte `json:"message"` // Raw payload bytes (e.g. serialized request/response body)
Metadata map[string]interface{} `json:"metadata,omitempty"` // Consolidated metadata

// Security & Non-Repudiation
Expand Down
2 changes: 1 addition & 1 deletion pkg/audit/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type SignPayloadFunc func(ctx context.Context, payload []byte) (signature string
// json.Marshal output is Go-specific (spacing, key ordering of maps, encoding of
// special characters) and is extremely difficult to reproduce byte-for-byte in other
// languages like Python or Node.js. By using a simple pipe-delimited format, any
// language in NSW's polyglot ecosystem can trivially compute the same canonical payload.
// language in a polyglot microservice ecosystem can trivially compute the same canonical payload.
//
// Canonical format (fields separated by "|"):
//
Expand Down
Loading