blob: a3521f8bd9322804e7169a3f4f32abc695d684b2 [file] [log] [blame]
local kube = import "../../../kube/kube.libsonnet";
{
IX: {
local ix = self,
local cfg = ix.cfg,
cfg:: {
image: "registry.k0.hswaw.net/bgpwtf/cccampix:1566584484-a2960f526c36de0dbcd911f05ee9db587e63eb9b",
octorpki: {
image: cfg.image,
storageClassName: "waw-hdd-redundant-2",
resources: {
requests: { cpu: "200m", memory: "1Gi" },
limits: { cpu: "1", memory: "2Gi" },
},
},
verifier: {
image: cfg.image,
domain: "ix-grpc.bgp.wtf",
db: {
host: "public.crdb-waw1.svc.cluster.local",
port: 26257,
username: "cccampix",
name: "cccampix",
tlsSecret: "client-cccampix-certificate",
},
},
pgpencryptor: {
image: cfg.image,
db: {
host: "public.crdb-waw1.svc.cluster.local",
port: 26257,
username: "cccampix",
name: "cccampix-pgpencryptor",
tlsSecret: "client-cccampix-certificate",
},
},
irr: {
image: cfg.image,
},
peeringdb: {
image: cfg.image,
},
frontend: {
domain: "ix-status.bgp.wtf",
image: cfg.image,
},
alice: {
domain: "ix-lg.bgp.wtf",
image: "registry.k0.hswaw.net/q3k/alice-lg:20190823-1557",
},
appName: "ix",
namespace: error "namespace must be defined",
prefix: "",
},
namespace: kube.Namespace(cfg.namespace),
name(component):: cfg.prefix + component,
metadata(component):: {
namespace: cfg.namespace,
labels: {
"app.kubernetes.io/name": cfg.appName,
"app.kubernetes.io/managed-by": "kubecfg",
"app.kubernetes.io/component": component,
},
},
octorpki: {
address:: "%s.%s.svc.cluster.local:%d" % [
"octorpki",
ix.cfg.namespace,
8080,
],
cache: kube.PersistentVolumeClaim(ix.name("octorpki")) {
metadata+: ix.metadata("octorpki"),
spec+: {
storageClassName: cfg.octorpki.storageClassName,
accessModes: [ "ReadWriteOnce" ],
resources: {
requests: {
storage: "2Gi",
},
},
},
},
deployment: kube.Deployment(ix.name("octorpki")) {
metadata+: ix.metadata("octorpki"),
spec+: {
template+: {
spec+: {
volumes_: {
cache: kube.PersistentVolumeClaimVolume(ix.octorpki.cache),
},
containers_: {
octorpki: kube.Container(ix.name("octorpki")){
image: cfg.octorpki.image,
args: [
"/octorpki/entrypoint.sh",
],
ports_: {
client: { containerPort: 8080 },
},
volumeMounts_: {
cache: { mountPath: "/cache" },
},
resources: cfg.octorpki.resources,
},
},
},
},
},
},
svc: kube.Service(ix.name("octorpki")) {
metadata+: ix.metadata("octorpki"),
target_pod:: ix.octorpki.deployment.spec.template,
spec+: {
ports: [
{ name: "client", port: 8080, targetPort: 8080, protocol: "TCP" },
],
},
},
},
component(name):: {
local component = self,
args:: error "args must be set",
name:: name,
port:: 4200,
volumes:: {},
volumeMounts:: {},
deployment: kube.Deployment(ix.name(name)) {
metadata+: ix.metadata(name),
spec+: {
template+: {
spec+: {
volumes_: component.volumes,
containers_: {
[name]: kube.Container(ix.name(name)) {
image: cfg[name].image,
args: component.args,
volumeMounts_: component.volumeMounts,
},
},
},
},
},
},
svc: kube.Service(ix.name(name)) {
metadata+: ix.metadata(name),
target_pod:: component.deployment.spec.template,
spec+: {
ports: [
{ name: "client", port: component.port, targetPort: component.port, protocol: "TCP" },
],
},
},
address:: "%s.%s.svc.cluster.local:%d" % [
component.name,
ix.cfg.namespace,
component.port,
],
},
irr: ix.component("irr") {
args: [
"/ix/irr",
"-hspki_disable",
"-listen_address=0.0.0.0:4200",
],
},
peeringdb: ix.component("peeringdb") {
args: [
"/ix/peeringdb",
"-hspki_disable",
"-listen_address=0.0.0.0:4200",
],
},
crdb:: {
volumes: {
tls: {
secret: {
secretName: cfg.verifier.db.tlsSecret,
defaultMode: kube.parseOctal("0400"),
},
},
},
volumeMounts: {
tls: {
mountPath: "/tls",
},
},
args(dbconf): [
"-dsn", "postgres://%s@%s:%d/%s?sslmode=require&sslrootcert=%s&sslcert=%s&sslkey=%s" % [
dbconf.username,
dbconf.host,
dbconf.port,
dbconf.name,
"/tls/ca.crt",
"/tls/tls.crt",
"/tls/tls.key",
],
]
},
verifier: ix.component("verifier") {
volumes: ix.crdb.volumes,
volumeMounts: ix.crdb.volumeMounts,
args: [
"/ix/verifier",
"-hspki_disable",
"-listen_address=0.0.0.0:4200",
"-peeringdb=" + ix.peeringdb.address,
"-irr=" + ix.irr.address,
"-octorpki=" + ix.octorpki.address,
"-pgpencryptor=" + ix.pgpencryptor.address,
] + ix.crdb.args(cfg.verifier.db),
},
pgpencryptor: ix.component("pgpencryptor") {
volumes: ix.crdb.volumes,
volumeMounts: ix.crdb.volumeMounts,
args: [
"/ix/pgpencryptor",
"-hspki_disable",
"-listen_address=0.0.0.0:4200",
] + ix.crdb.args(cfg.pgpencryptor.db),
},
frontend: ix.component("frontend") {
port: 8080,
args: [
"/ix/frontend.par",
"--flask_secret=dupa",
"--listen=0.0.0.0:8080",
"--verifier=" + ix.verifier.address,
],
},
alice: ix.component("alice") {
port: 7340,
volumes: {
config: kube.ConfigMapVolume(ix.alice.configMap),
theme: kube.ConfigMapVolume(ix.alice.themeMap),
},
volumeMounts: {
config: {
mountPath: "/etc/alice",
},
theme: {
mountPath: "/etc/alice-theme",
},
},
args: [
"/usr/bin/alice-lg",
"-config", "/etc/alice/alice",
],
themeMap: kube.ConfigMap(ix.name("alice-theme")) {
metadata+: ix.metadata("alice-theme"),
data: {
"content.js": |||
Alice.updateContent({
header: {
title: "CCCampIX Looking Glass",
tagline: "powered by alice-lg"
},
welcome: {
title: "CCCampIX Looking Glass",
tagline: "BGP to the tent."
}
});
|||,
},
},
configMap: kube.ConfigMap(ix.name("alice")) {
metadata+: ix.metadata("alice"),
data: {
config: |||
[server]
listen_http = 0.0.0.0:7340
enable_neighbors_status_refresh = false
asn = 208521
[housekeeping]
interval = 5
force_release_memory = true
[theme]
path = /etc/alice-theme
[pagination]
routes_filtered_page_size = 250
routes_accepted_page_size = 250
routes_not_exported_page_size = 250
[rejection_reasons]
208521:65666:1 = An IP Bogon was detected
208521:65666:2 = Prefix is longer than 64
208521:65666:3 = Prefix is longer than 24
208521:65666:4 = AS path contains a bogon AS
208521:65666:5 = AS path length is longer than 64
208521:65666:6 = BGP Path invalid (must be only peer)
208521:65666:9 = Prefix not found in RPKI for Origin AS
[neighbours_columns]
Description = Description
address = Neighbour
asn = ASN
state = State
Uptime = Uptime
routes_received = Routes Received
routes_filtered = Filtered
[routes_columns]
network = Network
gateway = Gateway
interface = Interface
metric = Metric
bgp.as_path = AS Path
[lookup_columns]
network = Network
gateway = Gateway
neighbour.asn = ASN
neighbour.description = Description
bgp.as_path = AS Path
routeserver.name = RS
[source.rs1-camp-v4]
name = rs1.camp.bgp.wtf (IPv4)
group = Camp
[source.rs1-camp-v4.birdwatcher]
timezone = UTC
api = http://isw01.camp.bgp.wtf:3000/
type = single_table
neighbors_refresh_timeout = 2
servertime = 2006-01-02T15:04:05Z
servertime_short = 2006-01-02 15:04:05
servertime_ext = 2006-01-02 15:04:05
[source.rs1-camp-v6]
name = rs1.camp.bgp.wtf (IPv6)
group = Camp
[source.rs1-camp-v6.birdwatcher]
timezone = UTC
api = http://isw01.camp.bgp.wtf:3001/
type = single_table
neighbors_refresh_timeout = 2
servertime = 2006-01-02T15:04:05Z
servertime_short = 2006-01-02 15:04:05
servertime_ext = 2006-01-02 15:04:05
[source.rs2-camp-v4]
name = rs2.camp.bgp.wtf (IPv4)
group = Camp
[source.rs2-camp-v4.birdwatcher]
timezone = UTC
api = http://isw01.camp.bgp.wtf:3002/
type = single_table
neighbors_refresh_timeout = 2
servertime = 2006-01-02T15:04:05Z
servertime_short = 2006-01-02 15:04:05
servertime_ext = 2006-01-02 15:04:05
[source.rs2-camp-v6]
name = rs2.camp.bgp.wtf (IPv6)
group = Camp
[source.rs2-camp-v6.birdwatcher]
timezone = UTC
api = http://isw01.camp.bgp.wtf:3003/
type = single_table
neighbors_refresh_timeout = 2
servertime = 2006-01-02T15:04:05Z
servertime_short = 2006-01-02 15:04:05
servertime_ext = 2006-01-02 15:04:05
|||,
},
},
},
ripeSync: kube.CronJob(ix.name("ripe-sync")) {
metadata+: ix.metadata("ripe-sync"),
spec+: {
schedule: "*/5 * * * *",
jobTemplate+: {
spec+: {
selector:: null,
template+: {
spec+: {
containers_: {
"ripe-sync": kube.Container(ix.name("ripe-sync")) {
image: cfg.image,
args: [
"/ix/ripe-sync.par",
"$(PASSWORD)",
ix.verifier.address,
],
env_: {
PASSWORD: {
secretKeyRef: {
name: ix.name("ripe-sync"),
key: "password",
},
},
},
},
},
},
},
},
},
},
},
ingress: kube.Ingress("ingress") {
metadata+: ix.metadata("public") {
annotations+: {
"kubernetes.io/tls-acme": "true",
"cert-manager.io/cluster-issuer": "letsencrypt-prod",
"nginx.ingress.kubernetes.io/proxy-body-size": "0",
},
},
spec+: {
tls: [
{ hosts: [cfg.frontend.domain], secretName: "public-tls"}
],
rules: [
{
host: cfg.frontend.domain,
http: {
paths: [
{ path: "/", backend: ix.frontend.svc.name_port },
],
},
},
],
},
},
aliceIngress: kube.Ingress("alice") {
metadata+: ix.metadata("alice") {
annotations+: {
"kubernetes.io/tls-acme": "true",
"cert-manager.io/cluster-issuer": "letsencrypt-prod",
"nginx.ingress.kubernetes.io/proxy-body-size": "0",
},
},
spec+: {
tls: [
{ hosts: [cfg.alice.domain], secretName: "alice-tls"}
],
rules: [
{
host: cfg.alice.domain,
http: {
paths: [
{ path: "/", backend: ix.alice.svc.name_port },
],
},
},
],
},
},
grpcIngress: kube.Ingress("grpc") {
metadata+: ix.metadata("grpc") {
annotations+: {
"kubernetes.io/tls-acme": "true",
"cert-manager.io/cluster-issuer": "letsencrypt-prod",
"kubernetes.io/ingress.class": "nginx",
"nginx.ingress.kubernetes.io/ssl-redirect": "true",
"nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
},
},
spec+: {
tls: [
{ hosts: [cfg.verifier.domain], secretName: "grpc-tls"}
],
rules: [
{
host: cfg.verifier.domain,
http: {
paths: [
{ path: "/", backend: ix.verifier.svc.name_port },
],
},
},
],
},
},
},
}