Skip to content

feat(build): Add multi-stage Dockerfile for management server#5172

Closed
obtFusi wants to merge 18 commits intonetbirdio:mainfrom
silentspike:feature/multistage-dockerfile
Closed

feat(build): Add multi-stage Dockerfile for management server#5172
obtFusi wants to merge 18 commits intonetbirdio:mainfrom
silentspike:feature/multistage-dockerfile

Conversation

@obtFusi
Copy link
Copy Markdown

@obtFusi obtFusi commented Jan 24, 2026

Summary

  • Adds Dockerfile.multistage for building management server with correct binary format
  • Solves ar archive issue (binary was library instead of executable)

Problem

Building with go build ./management/cmd/ produced an ar archive because cmd/ has package cmd, not package main.

Solution

  • Use ./management/ which has main.go with package main
  • Multi-stage build inside golang:1.25 container
  • No cross-compilation issues

Usage

docker build -f management/Dockerfile.multistage -t netbird-fork/management:latest .

Test plan

  • Binary is ELF executable (verified with file command)
  • Container starts successfully
  • mTLS server runs on port 33074
  • Deployed and tested on lab (10.0.0.103)

Relates to: #93

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added mTLS certificate-based authentication for machine peers with dedicated registration and management endpoints.
    • Introduced automated dependency updates via Dependabot configuration.
    • Added GitHub issue templates for structured bug reports, features, epics, stories, and tasks.
  • CI/CD Improvements

    • Implemented automatic issue and pull request labeling based on title analysis.
    • Added pull request linting to enforce consistent commit message conventions.
    • Configured pre-commit hooks for code quality checks.
  • Build & Infrastructure

    • Enhanced build system with multi-platform cross-compilation support.
    • Added containerized management service deployment.
    • Introduced lab automation scripts for testing environments.

✏️ Tip: You can customize this high-level summary in your review settings.

obtFusi and others added 18 commits January 18, 2026 02:54
- PR lint workflow (Conventional Commits validation)
- Auto-label workflow (Epic/Story/Task + type detection)
- Dependabot config (Go, Docker, GitHub Actions)
- Issue templates (Bug, Feature, Epic, Story, Task)
- PR template with checklist

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ci: add GitHub configuration from network-agent pattern
Implements server-side mTLS authentication infrastructure:

- MTLSIdentity extraction from client certificates
- SAN DNSName as primary identity (not CN!)
- Template OID (v2) and Template Name (v1) parsing
- BMPString (UTF-16BE) decoding for AD CS templates
- PeerType determination (machine/user/unknown)
- Issuer fingerprint via VerifiedChains (strong binding)
- gRPC interceptors (unary + stream) with method-based routing

Includes:
- ADR-001: mTLS Port Strategy
- ADR-002: CNG Signer Interface (for T-1.1)
- Test certificates for unit tests
- Comprehensive test coverage

Closes #14 (T-1.2)
Closes #15 (T-1.3)
Refs #13 (T-1.1 blocked - needs Windows)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security audit documents should not be committed to public repository.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
T-1.1: CNG crypto.Signer spike (spike/cng-signer/)
- Pure Go Windows CNG integration via golang.org/x/sys/windows
- Non-exportable private key signing with crypto.Signer interface
- Tested on DC01: 1.6ms signing latency, no CGO required
- Fixed CertDuplicateCertificateContext bug for context retention

T-1.3: SAN/Template parser spike (spike/san-parser/)
- Extracts SAN DNSName (primary identity, NOT CN)
- Parses AD CS Template OID/Name from extensions
- Determines PeerType (machine/user) from template analysis
- Tested on DC01: All checks passed

Also includes:
- scripts/lab/autounattend.xml for Windows VM provisioning

Closes #13, #15

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- setup-lab-ca.ps1: Automates AD CS setup, template creation, GPO
- verify-lab-ca.ps1: Validates CA configuration (7 checks)
- test-client-enrollment.ps1: Tests machine cert enrollment via SYSTEM context

Key improvements based on T-2.7 learnings:
- Machine cert enrollment requires SYSTEM context (Scheduled Task)
- Template created via ADSI with proper flags
- RPC port range restriction (5000-5100) for firewall

Closes #24

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix regex for CA name parsing (pipe to Out-String)
- Cast PropertyValueCollection to int for bitwise ops
- Fix GPO link check using Get-ADObject
- Fix RPC port range regex

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- RegisterMachinePeer, SyncMachinePeer, GetMachineRoutes, ReportMachineStatus
- MachineIdentity, MachineRegisterRequest/Response, MachineSyncRequest/Response
- MachineRoutesRequest/Response, MachineStatusRequest/Response
- MachineUpdateType enum

Refs #27

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements T-3.4: AllowedDomains pro-Account Scoping

- Add AccountID and MatchedDomain fields to MTLSIdentity struct
- Add MTLSDomainAccountMapping and MTLSAccountAllowedDomains config
- Implement getAccountIDFromDomain() for domain-to-account mapping
- Implement getAllowedDomainsForAccount() for per-account domain lists
- Implement validateDomainForAccount() for cross-tenant prevention
- Add checkMultiAccountSpan() for security logging
- Update extractMTLSIdentity() to validate against account domains
- Add comprehensive unit tests for account mapping

Security: Prevents cross-tenant certificate acceptance by validating
that certificate SANs match only the mapped account's allowed domains.
Fail-safe: No configured domains = reject all.

Closes #30

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement gRPC handlers for machine peer registration using mTLS:
- RegisterMachinePeer: Register machine peers via certificate auth
- SyncMachinePeer: Streaming sync for machine peers (stub)
- GetMachineRoutes: Retrieve DC routes for machine peers (stub)
- ReportMachineStatus: Machine status reporting

Architectural changes:
- Create shared/mtls package for Identity type to avoid import cycles
- Update mtls_auth.go to use shared Identity via type alias
- Remove duplicate GetMTLSIdentity function

The handlers extract mTLS identity from context (set by interceptor)
and use AccountID from domain-account mapping for multi-tenant isolation.

Closes #32

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ll mTLS support

Implements all features from Issue #32:

1. validateIssuerCA - CA-Fingerprint validation per account
   - Added MTLSAccountAllowedIssuers config field
   - ValidateIssuerCA function in shared/mtls package
   - Per Security Review: Empty allowlist = DENY (explicit config required)

2. Meta fields for audit trail
   - Extended PeerSystemMeta with mTLS-specific fields:
     - PeerType, AuthMethod, CertDNSName, CertDomain
     - CertIssuerFP, CertSerial, CertTemplate
     - FirstAuthTime, LastCertAuthTime
   - extractMachinePeerMeta enriches metadata with mTLS identity

3. Re-registration logic
   - LoginPeer handles both new and existing peers
   - Cross-account registration blocked (security check)
   - mTLS metadata updated on re-registration

4. Security validations
   - Issuer CA validation in all Machine Tunnel RPCs
   - Account isolation via MTLSIdentity.AccountID
   - Fingerprint-based comparison (not DN string matching)

5. Rate-limit/Replay protection: Stubbed for MVP (TODO)

Files changed:
- config/config.go: Added MTLSAccountAllowedIssuers
- mtls_auth.go: Added ValidateIssuerCA, MTLSConfig updated
- shared/mtls/identity.go: ValidatorConfig, ValidateIssuerCA
- shared/grpc/machine_tunnel.go: Full implementation
- server/peer/peer.go: Extended PeerSystemMeta with mTLS fields

Closes #32

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements unique DNS label generation for mTLS-authenticated peers
to prevent hostname collisions across different domains.

Features:
- GenerateUniqueDNSLabel: Creates FQDN-hash based labels
  Example: "win10-pc.customer-a.local" -> "win10-pc-a1b2c3d4"
- ValidateDNSLabel: RFC 1123 compliance check
- sanitizeForDNS: Hostname sanitization (underscores, spaces -> hyphens)
- CheckDNSLabelCollision: Helper for collision detection

Technical details:
- 32-bit SHA256 hash suffix (8 hex chars) for ~0.001% collision rate
- Automatic hostname truncation for labels > 63 chars
- Case-insensitive FQDN hashing
- Fallback to IP-based label on validation failure

Integration:
- AddPeer in peer.go now uses hash-based labels for mTLS peers
- Detection via peer.Meta.CertDNSName and peer.Meta.CertDomain fields

Unit tests:
- Uniqueness across domains/hostnames
- Truncation for long hostnames
- RFC 1123 validation (all edge cases)
- Sanitization (underscores, spaces, special chars)

Closes #33

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MTLSServer type with RequireAndVerifyClientCert on port 33074
- Add MTLSPort config option for dedicated mTLS-only server
- Integrate mTLS server lifecycle into BaseServer (Start/Stop)
- Add GetMTLSServer() for external service registration
- Load CA pool from directory (.crt/.pem/.cer) and/or single file
- Initialize mTLS validator config with account-issuer mappings
- TLS 1.2+ minimum required for mTLS connections

Port 33073 (standard): NoClientCert - user auth, setup keys
Port 33074 (mTLS): RequireAndVerifyClientCert - machine tunnel only

Closes #34

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix duplicate word 'LoginPeer' in comment (machine_tunnel.go)
- Convert if-else chains to switch statements (mtls_auth.go, peer.go)
- Add nolint directive for deprecated Audience field test (conversion_test.go)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
We had both .github/PULL_REQUEST_TEMPLATE.md (our custom) and
.github/pull_request_template.md (upstream). On macOS with its
case-insensitive filesystem, this causes git diff failures in CI.

Keep the upstream template (lowercase) for compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
We had both .github/PULL_REQUEST_TEMPLATE.md (our custom) and
.github/pull_request_template.md (upstream). On macOS with its
case-insensitive filesystem, this causes git diff failures in CI.

Keep the upstream template (lowercase) for compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(server): Complete S-3 Server mTLS Implementation
Adds Dockerfile.multistage that builds the management server binary
inside a golang:1.25 container, solving the ar archive issue.

Problem: Building with `go build ./management/cmd/` produced an ar
archive instead of an ELF executable because cmd/ has `package cmd`
(library), not `package main`.

Solution: Use `go build ./management/` which contains main.go with
`package main` and `func main()`.

Benefits:
- No cross-compilation issues (builds inside Linux container)
- Produces correct ELF binary (~52MB)
- Smaller final image (ubuntu:24.04 base)
- Build flags: -ldflags="-s -w" for smaller binary

Usage:
  docker build -f management/Dockerfile.multistage -t netbird-fork/management:latest .

Relates to: #93 (T-3.9: Deploy Fork to Lab)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@obtFusi
Copy link
Copy Markdown
Author

obtFusi commented Jan 24, 2026

Accidentally created on wrong repo. Intended for fork.

@obtFusi obtFusi closed this Jan 24, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 24, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This PR introduces comprehensive mTLS support for machine peers to the management service, including certificate-based authentication, identity extraction and validation, DNS label generation, and gRPC handlers. It also adds development workflow infrastructure (pre-commit hooks, issue templates, auto-labeling, PR linting) and lab setup scripts for testing AD CS-based certificate enrollment.

Changes

Cohort / File(s) Summary
Development Infrastructure
.githooks/pre-commit, Makefile, .gitignore
Pre-commit hook for Go formatting and secret scanning; Makefile updates for cross-platform builds and hook setup; .gitignore refinements for development artifacts and expanded ignore patterns
GitHub Workflows & Templates
.github/workflows/auto-label.yml, .github/workflows/pr-lint.yml, .github/ISSUE_TEMPLATE/*, .github/dependabot.yml, .github/ISSUE_TEMPLATE/config.yml
New GitHub Actions workflows for auto-labeling issues/PRs and enforcing conventional commits; issue templates (bug, epic, story, task, feature request); Dependabot config for Go modules, actions, and Docker; template configuration disabling blank issues
mTLS Core Infrastructure
management/internals/shared/mtls/identity.go, management/internals/shared/mtls/dnslabel.go, management/internals/shared/mtls/dnslabel_test.go, management/internals/shared/mtls/identity.go
New mTLS shared modules: Identity struct with context management, ValidatorConfig for per-account issuer validation; DNS label generation with RFC1123 compliance, collision detection, and hash-based uniqueness
Management Server mTLS
management/internals/server/mtls_auth.go, management/internals/server/mtls_auth_test.go, management/internals/server/mtls_server.go, management/internals/server/server.go, management/internals/server/boot.go, management/internals/server/config/config.go
mTLS interceptors (unary/stream), identity extraction, domain-account mapping, issuer fingerprint validation; dedicated mTLS gRPC server on port 33074; TLS configuration loading; CA certificate pool management; server lifecycle integration
Machine Tunnel gRPC
management/internals/shared/grpc/machine_tunnel.go, management/internals/shared/grpc/conversion_test.go, shared/management/proto/management.proto
New machine tunnel RPC handlers (RegisterMachinePeer, SyncMachinePeer, GetMachineRoutes, ReportMachineStatus) with mTLS identity extraction; proto messages (MachineIdentity, MachineRegisterRequest/Response, MachineSync*, MachineRoutes*, MachineStatus*); peer metadata enrichment
Peer Metadata & DNS
management/server/peer/peer.go, management/server/peer.go
PeerSystemMeta struct extended with mTLS fields (PeerType, AuthMethod, CertDNSName, CertDomain, CertIssuerFP, CertSerial, CertTemplate, FirstAuthTime, LastCertAuthTime); DNS label generation logic for mTLS peers
Docker & Proto
management/Dockerfile.multistage
Multi-stage Dockerfile for management service; builder stage compiles netbird-mgmt, final stage runs on ubuntu:24.04
Windows Certificate Handling (Spike)
spike/cng-signer/main.go, spike/cng-signer/go.mod, spike/san-parser/main.go, spike/san-parser/go.mod
Proof-of-concept implementations: CNGSigner for Windows CNG-backed crypto.Signer with non-exportable keys; SAN parser for certificate identity extraction and template information
Architecture & Design
docs/ADR-001-mTLS-Port-Strategy.md, docs/ADR-002-CNG-Signer-Interface.md
ADRs documenting mTLS port strategy (single port with method-based routing), Windows CNG signer interface, implementation components, and related decisions
Lab CA Infrastructure
scripts/lab/setup-lab-ca.ps1, scripts/lab/verify-lab-ca.ps1, scripts/lab/test-client-enrollment.ps1, scripts/lab/autounattend.xml
PowerShell scripts for bootstrapping AD CS environment, NetBirdMachine template creation, auto-enrollment GPO setup, lab verification with health checks, and client certificate enrollment testing; Windows unattended installation configuration
Test Certificates
test/certs/* (ca.crt, ca.key, ca.srl, client.crt, client.csr, client.key, client.cnf, server.crt, server.csr, server.key, server.cnf)
Test CA and client/server certificates with private keys and CSR configurations for mTLS testing

Sequence Diagram(s)

sequenceDiagram
    participant Client as Machine Peer
    participant TLS as TLS Layer
    participant Interceptor as gRPC Interceptor
    participant Identity as Identity Extractor
    participant Validator as ValidatorConfig
    participant Handler as RPC Handler
    
    Client->>TLS: Connect with client cert
    TLS->>Interceptor: Establish connection
    Interceptor->>Identity: Extract from TLS state
    Note over Identity: Parse SAN, Issuer FP,<br/>Template OID/Name
    Identity->>Validator: Validate issuer CA
    Validator-->>Validator: Check per-account<br/>allowlist
    alt Issuer Valid
        Validator-->>Identity: Success
        Identity->>Identity: Resolve domain→account
        Identity-->>Interceptor: Return MTLSIdentity
        Interceptor->>Handler: Inject into context
        Handler-->>Client: Process RPC
    else Issuer Invalid
        Validator-->>Identity: Forbidden
        Identity-->>Interceptor: Error
        Interceptor-->>Client: Reject (unauthenticated)
    end
Loading
sequenceDiagram
    participant Mgmt as Management Server
    participant Interceptor as mTLS Interceptor
    participant PeerMeta as PeerSystemMeta
    participant Manager as AccountManager
    participant Store as Peer Store
    
    Mgmt->>Interceptor: RegisterMachinePeer RPC
    Interceptor->>Interceptor: Extract MTLSIdentity
    Interceptor->>PeerMeta: Enrich peer metadata
    Note over PeerMeta: Add CertDNSName,<br/>CertIssuerFP,<br/>AuthMethod, etc.
    PeerMeta->>Manager: LoginPeer(enriched meta)
    Manager->>Store: Register/Update peer
    Store-->>Manager: Success
    Manager-->>Mgmt: Return registration response
    Mgmt-->>Mgmt: Generate DNS label
    Note over Mgmt: Hash-based unique label<br/>from domain/hostname
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • mlsmaycon
  • pappz
  • crn4

Poem

🐰 A rabbit hops through certificates so grand,
mTLS magic across the NetBird land!
Identity flowing through gRPC streams,
Secure machine peers living the dream—
DNS labels hash with cryptographic grace,
Trust and validation seal every trace! ✨

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
11 New issues
3 Security Hotspots
9 New Code Smells (required ≤ 0)
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

types: [opened]

permissions:
issues: write

Check notice

Code scanning / SonarCloud

Write permissions should be defined at the job level Low

Move this write permission from workflow level to job level. See more on SonarQube Cloud

permissions:
issues: write
pull-requests: write

Check notice

Code scanning / SonarCloud

Write permissions should be defined at the job level Low

Move this write permission from workflow level to job level. See more on SonarQube Cloud
@obtFusi obtFusi deleted the feature/multistage-dockerfile branch January 24, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants