Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
manast committed Aug 19, 2020
0 parents commit 0e150eb
Show file tree
Hide file tree
Showing 12 changed files with 1,815 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bin/
/node_modules/
2 changes: 2 additions & 0 deletions Pulumi.dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
config:
gcp:project: my-gcp-project
3 changes: 3 additions & 0 deletions Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: pulumi-external-dns
runtime: nodejs
description: A minimal Google Cloud TypeScript Pulumi program
153 changes: 153 additions & 0 deletions components/cluster.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import * as pulumi from "@pulumi/pulumi";

import * as gcp from "@pulumi/gcp";
import * as k8s from "@pulumi/kubernetes";

import { ComponentResource, CustomResourceOptions } from "@pulumi/pulumi";

export class Cluster extends ComponentResource {
provider: k8s.Provider;

constructor(
name: string,
location: string,
opts: CustomResourceOptions = {}
) {
super("taskforce:provisioner:Cluster", name, {}, opts);

const engineVersion = gcp.container
.getEngineVersions({ location })
.then((v) => v.latestMasterVersion);

const cluster = new gcp.container.Cluster(
name,
{
location,
initialNodeCount: 1,
minMasterVersion: engineVersion,
nodeVersion: engineVersion,
removeDefaultNodePool: true,
},
{ parent: this }
);

const nodePool = new gcp.container.NodePool(
"nodes",
{
location,
cluster: cluster.name,
nodeCount: 1,
autoscaling: {
maxNodeCount: 25,
minNodeCount: 1,
},
nodeConfig: {
machineType: "n1-standard-1",
diskType: "pd-ssd",
oauthScopes: [
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/ndev.clouddns.readwrite",

"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/trace.append",
"https://www.googleapis.com/auth/servicecontrol",
],
},
},
// { parent: this }
);

const kubeconfig = pulumi
.all([cluster.name, cluster.endpoint, cluster.masterAuth])
.apply(([name, endpoint, masterAuth]) => {
const context = `${gcp.config.project}_${location}_${name}`;
return `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${masterAuth.clusterCaCertificate}
server: https://${endpoint}
name: ${context}
contexts:
- context:
cluster: ${context}
user: ${context}
name: ${context}
current-context: ${context}
kind: Config
preferences: {}
users:
- name: ${context}
user:
auth-provider:
config:
cmd-args: config config-helper --format=json
cmd-path: gcloud
expiry-key: '{.credential.token_expiry}'
token-key: '{.credential.access_token}'
name: gcp
`;
});

// Create a Kubernetes provider instance that uses our cluster from above.
this.provider = new k8s.Provider(
name,
{
kubeconfig,
},
{ parent: this }
);

// Create a limited role for the `pulumi:devs` to use in the apps namespace.
let devsGroupRole = new k8s.rbac.v1.Role(
"pulumi-devs",
{
// metadata: { namespace: appNamespaceName },
rules: [
{
apiGroups: [""],
resources: [
"pods",
"secrets",
"services",
"persistentvolumeclaims",
],
verbs: ["get", "list", "watch", "create", "update", "delete"],
},
{
apiGroups: ["extensions", "apps"],
resources: ["replicasets", "deployments"],
verbs: ["get", "list", "watch", "create", "update", "delete"],
},
],
},
{ provider: this.provider, parent: this }
);

// Bind the `pulumi:devs` RBAC group to the new, limited role.
let devsGroupRoleBinding = new k8s.rbac.v1.RoleBinding(
"pulumi-devs",
{
// metadata: { namespace: appNamespaceName },
subjects: [
{
kind: "Group",
name: "pulumi:devs",
},
],
roleRef: {
kind: "Role",
name: devsGroupRole.metadata.name,
apiGroup: "rbac.authorization.k8s.io",
},
},
{ provider: this.provider, parent: this }
);

this.registerOutputs({
provider: this.provider,
});
}
}
114 changes: 114 additions & 0 deletions components/external-dns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import * as gcp from "@pulumi/gcp";
import * as k8s from "@pulumi/kubernetes";

import * as config from "../config";
import * as util from "../util";
import {
ProviderResource,
ComponentResource,
CustomResourceOptions,
} from "@pulumi/pulumi";

export class ExternalDns extends ComponentResource {
constructor(
name: string,
location: string,
provider: ProviderResource,
opts: CustomResourceOptions = {}
) {
super("taskforce:provisioner:external-dns", name, {}, opts);

const dnsName = `*.${location}.taskforce.run.`;

/*
const provisionsZone = new gcp.dns.ManagedZone(
"taskforce-zone-provisions",
{
description: "DNS zone for redis provisions",
dnsName,
labels: {},
},
{ parent: this }
);
*/
const serviceAccount = new gcp.serviceaccount.Account(
"externalDnsServiceAccount",
{
project: config.project,
accountId: `${name}-external-dns`,
displayName: `External DNS service account for ${name}`,
},
{ parent: this }
);

// Bind the admin ServiceAccount to be a GKE cluster admin.
util.bindToRole(
`${name}-external-dns-bind`,
serviceAccount,
{
project: config.project,
roles: ["roles/dns.admin"],
},
{ parent: serviceAccount }
);

const serviceAccountKey = util.createServiceAccountKey(
"externalDnsServiceAccountKey",
serviceAccount,
{ parent: serviceAccount, additionalSecretOutputs: ["privateKey"] }
);

const serviceAccountKeySecret = util.clientSecret(serviceAccountKey);

const serviceAccountSecret = new k8s.core.v1.Secret(
"external-dns-secret",
{
type: "Opaque",
stringData: {
"credentials.json": serviceAccountKey.privateKey.apply((x) =>
Buffer.from(x, "base64").toString("utf8")
),
},
},
{ provider, parent: serviceAccount }
);

const externalDns = new k8s.helm.v3.Chart(
"external-dns",
{
repo: "bitnami",
chart: "external-dns",
// version: "2.21.2",
values: {
provider: "google",
google: {
project: config.project,
serviceAccountSecret: serviceAccountSecret.id,
// serviceAccountSecretKey: "credentials.json",
// serviceAccountKey: serviceAccountKey.id,
},
serviceAccountKeySecret: {
create: false,
name: serviceAccountKey.id,
},
policy: "sync",
registry: "txt",
txtOwnerId: "k8s",
domainFilters: [dnsName],
/*
rbac: {
create: true,
apiVersion: "v1",
},
*/
},
},
{
provider,
parent: this,
dependsOn: [serviceAccountKey, serviceAccountSecret],
}
);
}
}
22 changes: 22 additions & 0 deletions config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2016-2019, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { Config } from "@pulumi/pulumi";

//
// GCP-specific config.
//

// project is the GCP project you are going to deploy to.
export const project = new Config("gcp").require("project");
12 changes: 12 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

import { ExternalDns } from "./components/external-dns";
import { Cluster } from "./components/cluster";

const name = "provisioner";
const location = "europe-north1";

const cluster = new Cluster(`cluster-${name}`, location);

const externalDns = new ExternalDns(`my-external-dns`, location, cluster.provider);
Loading

0 comments on commit 0e150eb

Please sign in to comment.