245 lines
7.3 KiB
TypeScript
245 lines
7.3 KiB
TypeScript
import * as pulumi from "@pulumi/pulumi";
|
|
import * as command from "@pulumi/command";
|
|
|
|
// =============================================================================
|
|
// NetBird API Client using Pulumi Command Provider
|
|
// =============================================================================
|
|
// Since there's no TypeScript SDK for NetBird, we use the command provider
|
|
// to make API calls. This demonstrates the pattern while being practical.
|
|
|
|
export interface NetBirdConfig {
|
|
url: string;
|
|
token: pulumi.Output<string>;
|
|
}
|
|
|
|
export interface GroupArgs {
|
|
name: string;
|
|
peers?: string[];
|
|
}
|
|
|
|
export interface PolicyRuleArgs {
|
|
name: string;
|
|
description?: string;
|
|
enabled: boolean;
|
|
sources: pulumi.Input<string>[];
|
|
destinations: pulumi.Input<string>[];
|
|
bidirectional: boolean;
|
|
protocol: string;
|
|
action: "accept" | "drop";
|
|
}
|
|
|
|
export interface PolicyArgs {
|
|
name: string;
|
|
description?: string;
|
|
enabled: boolean;
|
|
rules: PolicyRuleArgs[];
|
|
}
|
|
|
|
export interface SetupKeyArgs {
|
|
name: string;
|
|
type: "one-off" | "reusable";
|
|
autoGroups: pulumi.Input<string>[];
|
|
usageLimit: number;
|
|
expiresIn: number;
|
|
ephemeral: boolean;
|
|
}
|
|
|
|
// =============================================================================
|
|
// NetBird Group Resource
|
|
// =============================================================================
|
|
export class Group extends pulumi.ComponentResource {
|
|
public readonly id: pulumi.Output<string>;
|
|
public readonly name: string;
|
|
|
|
constructor(
|
|
name: string,
|
|
args: GroupArgs,
|
|
config: NetBirdConfig,
|
|
opts?: pulumi.ComponentResourceOptions
|
|
) {
|
|
super("netbird:custom:Group", name, {}, opts);
|
|
|
|
const createCmd = new command.local.Command(
|
|
`${name}-create`,
|
|
{
|
|
create: pulumi.interpolate`curl -s -X POST \
|
|
-H "Authorization: Token ${config.token}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "${args.name}", "peers": ${JSON.stringify(args.peers || [])}}' \
|
|
${config.url}/api/groups`,
|
|
delete: pulumi.interpolate`GROUP_ID=$(curl -s -H "Authorization: Token ${config.token}" \
|
|
${config.url}/api/groups | jq -r '.[] | select(.name=="${args.name}") | .id') && \
|
|
curl -s -X DELETE -H "Authorization: Token ${config.token}" \
|
|
${config.url}/api/groups/$GROUP_ID`,
|
|
},
|
|
{ parent: this }
|
|
);
|
|
|
|
this.id = createCmd.stdout.apply((stdout): string => {
|
|
try {
|
|
const result = JSON.parse(stdout);
|
|
return result.id || "";
|
|
} catch {
|
|
return "";
|
|
}
|
|
});
|
|
this.name = args.name;
|
|
|
|
this.registerOutputs({
|
|
id: this.id,
|
|
name: this.name,
|
|
});
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// NetBird Policy Resource
|
|
// =============================================================================
|
|
export class Policy extends pulumi.ComponentResource {
|
|
public readonly id: pulumi.Output<string>;
|
|
public readonly name: string;
|
|
|
|
constructor(
|
|
name: string,
|
|
args: PolicyArgs,
|
|
config: NetBirdConfig,
|
|
opts?: pulumi.ComponentResourceOptions
|
|
) {
|
|
super("netbird:custom:Policy", name, {}, opts);
|
|
|
|
// Build the policy payload
|
|
const rules = args.rules.map((rule) => ({
|
|
name: rule.name,
|
|
description: rule.description || "",
|
|
enabled: rule.enabled,
|
|
sources: rule.sources,
|
|
destinations: rule.destinations,
|
|
bidirectional: rule.bidirectional,
|
|
protocol: rule.protocol,
|
|
action: rule.action,
|
|
}));
|
|
|
|
const createCmd = new command.local.Command(
|
|
`${name}-create`,
|
|
{
|
|
create: pulumi.all([config.token, ...args.rules.flatMap(r => [...r.sources, ...r.destinations])]).apply(
|
|
([token, ...groupIds]) => {
|
|
const payload = {
|
|
name: args.name,
|
|
description: args.description || "",
|
|
enabled: args.enabled,
|
|
rules: args.rules.map((rule, i) => ({
|
|
name: rule.name,
|
|
description: rule.description || "",
|
|
enabled: rule.enabled,
|
|
sources: rule.sources,
|
|
destinations: rule.destinations,
|
|
bidirectional: rule.bidirectional,
|
|
protocol: rule.protocol,
|
|
action: rule.action,
|
|
})),
|
|
};
|
|
return `curl -s -X POST \
|
|
-H "Authorization: Token ${token}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '${JSON.stringify(payload)}' \
|
|
${config.url}/api/policies`;
|
|
}
|
|
),
|
|
delete: pulumi.interpolate`POLICY_ID=$(curl -s -H "Authorization: Token ${config.token}" \
|
|
${config.url}/api/policies | jq -r '.[] | select(.name=="${args.name}") | .id') && \
|
|
curl -s -X DELETE -H "Authorization: Token ${config.token}" \
|
|
${config.url}/api/policies/$POLICY_ID`,
|
|
},
|
|
{ parent: this }
|
|
);
|
|
|
|
this.id = createCmd.stdout.apply((stdout): string => {
|
|
try {
|
|
const result = JSON.parse(stdout);
|
|
return result.id || "";
|
|
} catch {
|
|
return "";
|
|
}
|
|
});
|
|
this.name = args.name;
|
|
|
|
this.registerOutputs({
|
|
id: this.id,
|
|
name: this.name,
|
|
});
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// NetBird Setup Key Resource
|
|
// =============================================================================
|
|
export class SetupKey extends pulumi.ComponentResource {
|
|
public readonly id: pulumi.Output<string>;
|
|
public readonly key: pulumi.Output<string>;
|
|
public readonly name: string;
|
|
|
|
constructor(
|
|
name: string,
|
|
args: SetupKeyArgs,
|
|
config: NetBirdConfig,
|
|
opts?: pulumi.ComponentResourceOptions
|
|
) {
|
|
super("netbird:custom:SetupKey", name, {}, opts);
|
|
|
|
const createCmd = new command.local.Command(
|
|
`${name}-create`,
|
|
{
|
|
create: pulumi.all([config.token, ...args.autoGroups]).apply(
|
|
([token, ...groupIds]) => {
|
|
const payload = {
|
|
name: args.name,
|
|
type: args.type,
|
|
auto_groups: groupIds,
|
|
usage_limit: args.usageLimit,
|
|
expires_in: args.expiresIn,
|
|
ephemeral: args.ephemeral,
|
|
};
|
|
return `curl -s -X POST \
|
|
-H "Authorization: Token ${token}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '${JSON.stringify(payload)}' \
|
|
${config.url}/api/setup-keys`;
|
|
}
|
|
),
|
|
delete: pulumi.interpolate`KEY_ID=$(curl -s -H "Authorization: Token ${config.token}" \
|
|
${config.url}/api/setup-keys | jq -r '.[] | select(.name=="${args.name}") | .id') && \
|
|
curl -s -X DELETE -H "Authorization: Token ${config.token}" \
|
|
${config.url}/api/setup-keys/$KEY_ID`,
|
|
},
|
|
{ parent: this }
|
|
);
|
|
|
|
this.id = createCmd.stdout.apply((stdout): string => {
|
|
try {
|
|
const result = JSON.parse(stdout);
|
|
return result.id || "";
|
|
} catch {
|
|
return "";
|
|
}
|
|
});
|
|
|
|
this.key = createCmd.stdout.apply((stdout): string => {
|
|
try {
|
|
const result = JSON.parse(stdout);
|
|
return result.key || "";
|
|
} catch {
|
|
return "";
|
|
}
|
|
});
|
|
|
|
this.name = args.name;
|
|
|
|
this.registerOutputs({
|
|
id: this.id,
|
|
key: this.key,
|
|
name: this.name,
|
|
});
|
|
}
|
|
}
|