added groups and users
All checks were successful
Pulumi / pulumi (push) Successful in 22s

This commit is contained in:
Prox
2026-02-15 17:27:44 +02:00
parent 3dd232228e
commit 6ba45d8f39
2 changed files with 212 additions and 130 deletions

144
config.ts Normal file
View File

@@ -0,0 +1,144 @@
// =============================================================================
// NetBird Configuration
// =============================================================================
// Edit this file to add/modify groups, policies, and setup keys.
// Changes are applied via CI/CD when merged to main.
export interface GroupConfig {
name: string;
description?: string;
}
export interface PolicyRuleConfig {
name: string;
description?: string;
sources: string[]; // Group names
destinations: string[]; // Group names
bidirectional?: boolean;
protocol?: string;
}
export interface PolicyConfig {
name: string;
description?: string;
rules: PolicyRuleConfig[];
}
export interface SetupKeyConfig {
name: string;
groups: string[]; // Group names
type?: "one-off" | "reusable";
expiresInDays?: number; // 0 = never
usageLimit?: number; // 0 = unlimited
}
// =============================================================================
// GROUPS
// =============================================================================
// Add new groups here. They define logical groupings of peers.
export const groups: GroupConfig[] = [
{ name: "ground-stations", description: "Ground station devices" },
{ name: "pilots", description: "Pilot control stations" },
{ name: "operators", description: "Operator workstations" },
{ name: "fusion-servers", description: "Data fusion servers" },
// Add new groups below:
// { name: "maintenance", description: "Maintenance team devices" },
];
// =============================================================================
// POLICIES
// =============================================================================
// Define access control between groups.
export const policies: PolicyConfig[] = [
{
name: "pilot-to-ground-station",
description: "Allow pilots to connect to ground stations",
rules: [
{
name: "pilot-gs-access",
description: "Pilots can access ground stations",
sources: ["pilots"],
destinations: ["ground-stations"],
bidirectional: true,
protocol: "all",
},
],
},
{
name: "operator-full-access",
description: "Operators can access all network resources",
rules: [
{
name: "operator-all",
description: "Full operator access",
sources: ["operators"],
destinations: ["ground-stations", "pilots", "fusion-servers"],
bidirectional: true,
protocol: "all",
},
],
},
{
name: "fusion-to-ground-station",
description: "Fusion servers coordinate with ground stations",
rules: [
{
name: "fusion-gs",
description: "Fusion to GS access",
sources: ["fusion-servers"],
destinations: ["ground-stations"],
bidirectional: true,
protocol: "all",
},
],
},
// Add new policies below:
// {
// name: "maintenance-access",
// description: "Maintenance team can access all devices",
// rules: [
// {
// name: "maintenance-all",
// sources: ["maintenance"],
// destinations: ["ground-stations", "pilots", "fusion-servers"],
// bidirectional: true,
// protocol: "all",
// },
// ],
// },
];
// =============================================================================
// SETUP KEYS
// =============================================================================
// Setup keys for enrolling new peers.
export const setupKeys: SetupKeyConfig[] = [
{
name: "ground-station-onboarding",
groups: ["ground-stations"],
type: "reusable",
expiresInDays: 0, // Never expires
usageLimit: 0, // Unlimited
},
{
name: "pilot-onboarding",
groups: ["pilots"],
type: "reusable",
expiresInDays: 30,
usageLimit: 0,
},
// Add new setup keys below:
// {
// name: "operator-onboarding",
// groups: ["operators"],
// type: "reusable",
// expiresInDays: 7,
// usageLimit: 10,
// },
];

198
index.ts
View File

@@ -1,5 +1,6 @@
import * as pulumi from "@pulumi/pulumi"; import * as pulumi from "@pulumi/pulumi";
import { Group, Policy, SetupKey, NetBirdConfig } from "./netbird"; import { Group, Policy, SetupKey, NetBirdConfig } from "./netbird";
import { groups as groupConfigs, policies as policyConfigs, setupKeys as setupKeyConfigs } from "./config";
// ============================================================================= // =============================================================================
// Configuration // Configuration
@@ -11,154 +12,91 @@ const netbirdConfig: NetBirdConfig = {
}; };
// ============================================================================= // =============================================================================
// Groups - Achilles Network Structure // Create Groups from Config
// ============================================================================= // =============================================================================
const groups = { const groups: Record<string, Group> = {};
groundStations: new Group(
"ground-stations",
{ name: "ground-stations", peers: [] },
netbirdConfig
),
pilots: new Group("pilots", { name: "pilots", peers: [] }, netbirdConfig),
operators: new Group(
"operators",
{ name: "operators", peers: [] },
netbirdConfig
),
fusionServers: new Group(
"fusion-servers",
{ name: "fusion-servers", peers: [] },
netbirdConfig
),
};
// ============================================================================= for (const cfg of groupConfigs) {
// Policies - Access Control groups[cfg.name] = new Group(
// ============================================================================= cfg.name,
const policies = { { name: cfg.name, peers: [] },
pilotToGs: new Policy( netbirdConfig
"pilot-to-ground-station", );
{
name: "pilot-to-ground-station",
description: "Allow pilots to connect to ground stations",
enabled: true,
rules: [
{
name: "pilot-gs-access",
description: "Pilots can access ground stations",
enabled: true,
sources: [groups.pilots.id],
destinations: [groups.groundStations.id],
bidirectional: true,
protocol: "all",
action: "accept",
},
],
},
netbirdConfig,
{ dependsOn: [groups.pilots, groups.groundStations] }
),
operatorFullAccess: new Policy(
"operator-full-access",
{
name: "operator-full-access",
description: "Operators can access all network resources",
enabled: true,
rules: [
{
name: "operator-all",
description: "Full operator access",
enabled: true,
sources: [groups.operators.id],
destinations: [
groups.groundStations.id,
groups.pilots.id,
groups.fusionServers.id,
],
bidirectional: true,
protocol: "all",
action: "accept",
},
],
},
netbirdConfig,
{
dependsOn: [
groups.operators,
groups.groundStations,
groups.pilots,
groups.fusionServers,
],
} }
),
fusionToGs: new Policy( // =============================================================================
"fusion-to-ground-station", // Create Policies from Config
{ // =============================================================================
name: "fusion-to-ground-station", const policies: Record<string, Policy> = {};
description: "Fusion servers coordinate with ground stations",
for (const cfg of policyConfigs) {
// Resolve group names to group IDs
const rules = cfg.rules.map((rule) => ({
name: rule.name,
description: rule.description || "",
enabled: true, enabled: true,
rules: [ sources: rule.sources.map((name) => groups[name].id),
destinations: rule.destinations.map((name) => groups[name].id),
bidirectional: rule.bidirectional ?? true,
protocol: rule.protocol || "all",
action: "accept" as const,
}));
// Collect all referenced groups for dependencies
const referencedGroups = [
...new Set([
...cfg.rules.flatMap((r) => r.sources),
...cfg.rules.flatMap((r) => r.destinations),
]),
].map((name) => groups[name]);
policies[cfg.name] = new Policy(
cfg.name,
{ {
name: "fusion-gs", name: cfg.name,
description: "Fusion to GS access", description: cfg.description || "",
enabled: true, enabled: true,
sources: [groups.fusionServers.id], rules,
destinations: [groups.groundStations.id],
bidirectional: true,
protocol: "all",
action: "accept",
},
],
}, },
netbirdConfig, netbirdConfig,
{ dependsOn: [groups.fusionServers, groups.groundStations] } { dependsOn: referencedGroups }
), );
}; }
// ============================================================================= // =============================================================================
// Setup Keys - Peer Onboarding // Create Setup Keys from Config
// ============================================================================= // =============================================================================
const setupKeys = { const setupKeys: Record<string, SetupKey> = {};
gsOnboarding: new SetupKey(
"ground-station-onboarding", for (const cfg of setupKeyConfigs) {
const referencedGroups = cfg.groups.map((name) => groups[name]);
setupKeys[cfg.name] = new SetupKey(
cfg.name,
{ {
name: "ground-station-onboarding", name: cfg.name,
type: "reusable", type: cfg.type || "reusable",
autoGroups: [groups.groundStations.id], autoGroups: cfg.groups.map((name) => groups[name].id),
usageLimit: 0, usageLimit: cfg.usageLimit ?? 0,
expiresIn: 0, expiresIn: (cfg.expiresInDays ?? 0) * 24 * 60 * 60, // Convert days to seconds
ephemeral: false, ephemeral: false,
}, },
netbirdConfig, netbirdConfig,
{ dependsOn: [groups.groundStations] } { dependsOn: referencedGroups }
), );
}
pilotOnboarding: new SetupKey(
"pilot-onboarding",
{
name: "pilot-onboarding",
type: "reusable",
autoGroups: [groups.pilots.id],
usageLimit: 0,
expiresIn: 2592000, // 30 days
ephemeral: false,
},
netbirdConfig,
{ dependsOn: [groups.pilots] }
),
};
// ============================================================================= // =============================================================================
// Outputs // Outputs
// ============================================================================= // =============================================================================
export const groupIds = { export const groupIds = Object.fromEntries(
groundStations: groups.groundStations.id, Object.entries(groups).map(([name, group]) => [name, group.id])
pilots: groups.pilots.id, );
operators: groups.operators.id,
fusionServers: groups.fusionServers.id,
};
export const gsSetupKey = pulumi.secret(setupKeys.gsOnboarding.key); export const policyIds = Object.fromEntries(
export const pilotSetupKey = pulumi.secret(setupKeys.pilotOnboarding.key); Object.entries(policies).map(([name, policy]) => [name, policy.id])
);
export const setupKeyValues = Object.fromEntries(
Object.entries(setupKeys).map(([name, key]) => [name, pulumi.secret(key.key)])
);