Merge branch 'ryansquared/k8s-cluster'

This commit is contained in:
Shane Engelman 2023-07-28 00:05:37 -04:00
commit 8071c60c4f
Signed by: shane
GPG Key ID: D9DF703B83B9A9B5
96 changed files with 9675 additions and 992 deletions

View File

@ -10,7 +10,8 @@ SOPS := $(ROOT_DIR)/out/sops
KEYS := \ KEYS := \
6B61ECD76088748C70590D55E90A401336C8AAA9 \ 6B61ECD76088748C70590D55E90A401336C8AAA9 \
88823A75ECAA786B0FF38B148E401478A3FBEF72 \ 88823A75ECAA786B0FF38B148E401478A3FBEF72 \
3D7C8D39E8C4DF771583D3F0A8A091FD346001CA 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA \
F4BF5C81EC78A5DD341C91EEDC4B7D1F52E0BA4D
.DEFAULT_GOAL := .DEFAULT_GOAL :=
.PHONY: default .PHONY: default
@ -56,14 +57,14 @@ $(OUT_DIR)/website/index.html: \
") ")
infra/backend/.terraform: \ infra/backend/.terraform: \
$(OUT_DIR)/terraform \ $(TERRAFORM) \
$(BACKEND_TF) $(BACKEND_TF)
$(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\ $(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\
env -C infra/backend $(TERRAFORM) init -upgrade \ env -C infra/backend $(TERRAFORM) init -upgrade \
' '
infra/main/.terraform: | \ infra/main/.terraform: | \
$(OUT_DIR)/terraform \ $(TERRAFORM) \
config/$(ENVIRONMENT).tfbackend \ config/$(ENVIRONMENT).tfbackend \
$(MAIN_TF) $(MAIN_TF)
$(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\ $(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\
@ -72,8 +73,8 @@ infra/main/.terraform: | \
' '
infra/backend/$(ENVIRONMENT).tfstate: \ infra/backend/$(ENVIRONMENT).tfstate: \
$(OUT_DIR)/terraform \ $(TERRAFORM) \
$(OUT_DIR)/sops \ $(SOPS) \
infra/backend/.terraform infra/backend/.terraform
$(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\ $(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\
env -C infra/backend \ env -C infra/backend \
@ -85,8 +86,8 @@ infra/backend/$(ENVIRONMENT).tfstate: \
' '
config/$(ENVIRONMENT).tfbackend: | \ config/$(ENVIRONMENT).tfbackend: | \
$(OUT_DIR)/terraform $(TERRAFORM) \
$(OUT_DIR)/sops \ $(SOPS) \
# File is not committed and this has no shared state # File is not committed and this has no shared state
$(MAKE) infra/backend/$(ENVIRONMENT).tfstate $(MAKE) infra/backend/$(ENVIRONMENT).tfstate
$(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\ $(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\
@ -98,9 +99,13 @@ config/$(ENVIRONMENT).tfbackend: | \
.PHONY: .PHONY:
apply: \ apply: \
$(OUT_DIR)/terraform \ $(TERRAFORM) \
$(OUT_DIR)/sops \ $(SOPS) \
infra/main/.terraform infra/main/.terraform
$(call maybe_decrypt_secret,secrets/$(ENVIRONMENT).talosconfig,infra/main/talos/talosconfig)
$(call maybe_decrypt_secret,secrets/$(ENVIRONMENT).kubeconfig,infra/main/talos/kubeconfig)
$(call maybe_decrypt_secret,secrets/$(ENVIRONMENT).controlplane.yaml,infra/main/talos/controlplane.yaml)
$(call maybe_decrypt_secret,secrets/$(ENVIRONMENT).worker.yaml,infra/main/talos/worker.yaml)
$(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\ $(SOPS) exec-env secrets/$(ENVIRONMENT).enc.env '\
env -C infra/main \ env -C infra/main \
$(TERRAFORM) apply \ $(TERRAFORM) apply \
@ -108,10 +113,10 @@ apply: \
-var namespace=$(ENVIRONMENT) \ -var namespace=$(ENVIRONMENT) \
-var region=$(REGION) \ -var region=$(REGION) \
' '
$(SOPS) --encrypt infra/main/talos/talosconfig > secrets/$(ENVIRONMENT).talosconfig $(call maybe_encrypt_secret,infra/main/talos/talosconfig,secrets/$(ENVIRONMENT).talosconfig)
$(SOPS) --encrypt infra/main/talos/kubeconfig > secrets/$(ENVIRONMENT).kubeconfig $(call maybe_encrypt_secret,infra/main/talos/kubeconfig,secrets/$(ENVIRONMENT).kubeconfig)
$(SOPS) --encrypt infra/main/talos/controlplane.yaml > secrets/$(ENVIRONMENT).controlplane.yaml $(call maybe_encrypt_secret,infra/main/talos/controlplane.yaml,secrets/$(ENVIRONMENT).controlplane.yaml)
$(SOPS) --encrypt infra/main/talos/worker.yaml > secrets/$(ENVIRONMENT).worker.yaml $(call maybe_encrypt_secret,infra/main/talos/worker.yaml,secrets/$(ENVIRONMENT).worker.yaml)
$(CACHE_DIR)/secrets: $(CACHE_DIR)/secrets:
mkdir -p $@ mkdir -p $@
@ -122,6 +127,9 @@ $(FETCH_DIR)/terraform:
$(FETCH_DIR)/sops: $(FETCH_DIR)/sops:
$(call git_clone,$@,$(SOPS_REPO),$(SOPS_REF)) $(call git_clone,$@,$(SOPS_REPO),$(SOPS_REF))
$(FETCH_DIR)/talosctl:
$(call git_clone,$@,$(TALOSCTL_REPO),$(TALOSCTL_REF))
$(OUT_DIR)/terraform: $(FETCH_DIR)/terraform $(OUT_DIR)/terraform: $(FETCH_DIR)/terraform
$(call toolchain," \ $(call toolchain," \
cd $(FETCH_DIR)/terraform && \ cd $(FETCH_DIR)/terraform && \
@ -148,3 +156,38 @@ $(OUT_DIR)/sops: $(FETCH_DIR)/sops
-ldflags='-w -extldflags=-static' \ -ldflags='-w -extldflags=-static' \
-o /home/build/$@ $(SOPS_PKG) \ -o /home/build/$@ $(SOPS_PKG) \
") ")
$(OUT_DIR)/talosctl: $(FETCH_DIR)/talosctl
$(call toolchain," \
cd $(FETCH_DIR)/talosctl && \
export CGO_ENABLED=0 && \
export GOCACHE=/home/build/$(CACHE_DIR) && \
export GOPATH=/home/build/$(CACHE_DIR) && \
go build \
-v \
-trimpath \
-ldflags='-w -extldflags=-static' \
-o /home/build/$@ $(TALOSCTL_PKG) \
")
# Note: Decryption MUST reset the mod time to avoid encryption/decryption loops
# Encrypt if:
# - Both files exist, local is newer than remote
# - Only local exists
define maybe_encrypt_secret
test \( -f $(1) -a -f $(2) -a $(1) -nt $(2) \) -o \
\( -f $(1) -a ! -f $(2) \) && \
$(SOPS) --encrypt $(1) > $(2) || true
endef
# Only decrypt when local files don't exist
# Unfortunately, this means we can't decrypt if the secrets update. We can't
# do that because otherwise it creates a loop. The secrets update, therefore we
# decrypt secrets, but because the modtime of the decrypted secrets is newer
# than the encrypted secrets, we want to reencrypt encrypted secrets.
define maybe_decrypt_secret
test -f $(1) -a ! -f $(2) && \
$(SOPS) --decrypt $(1) > $(2) && \
touch -d 1970-01-01 $(2) || \
true
endef

View File

@ -4,3 +4,6 @@ TERRAFORM_REPO=https://github.com/hashicorp/terraform
SOPS_REF=86f500de6102f5219e3fd0a25c718db01a7d39ed SOPS_REF=86f500de6102f5219e3fd0a25c718db01a7d39ed
SOPS_REPO=https://github.com/mozilla/sops SOPS_REPO=https://github.com/mozilla/sops
SOPS_PKG=go.mozilla.org/sops/v3/cmd/sops SOPS_PKG=go.mozilla.org/sops/v3/cmd/sops
TALOSCTL_REF=a2cc92b8a54e42fc2554d49e4e2147a57fba69cb
TALOSCTL_REPO=https://github.com/siderolabs/talos
TALOSCTL_PKG=github.com/siderolabs/talos/cmd/talosctl

View File

@ -0,0 +1,19 @@
Kustomizations should be deployed in a specific order to ensure Custom Resource
Definitions or Services used by additional Kustomizations have been deployed
before the Kustomization exists.
Current order:
* Cilium
* DigitalOcean Secrets
* Cert Manager (Deploy twice)
* DigitalOcean (Deploy twice)
* Ingress NGINX
* External DNS
* Keycloak
* Forgejo
Any secrets necessary for any of the previous Kustomizations can be generated
via scripts in the relevant Kustomization. There should be information in the
Kustomization's README (which may be in a `docs` subdirectory) about how to
generate the secrets.

View File

@ -0,0 +1,55 @@
# Encrypting
To encrypt a Kubernetes `v1/Secret` with sops from the command line:
```sh
sops --encrypt --encrypted-regex '^(data|stringData)$' --input-type=json --output-type=yaml <file>
```
`sops` does not recognize `-` as standard input, so to use standard input on
Linux systems you can use `/dev/stdin`. Input type is set to `json` assuming
the file passed in will be generated by `terraform`, but if made by hand can
be set to `yaml` or, if using a filepath, omitted entirely.
When a secret is available in Terraform's output, the following pattern can be
used to extract the secret from Terraform and encrypt it to a Kubernetes
Secret:
```sh
sops exec-env secrets/production.env \
'terraform c-chdir=infra/main output -json' \
| jq '.database_users.value.keycloak' \
| sops --encrypt --encrypted-regex '^(data|stringData)' --input-type=json --output-type=yaml /dev/stdin \
> kustomizations/keycloak/postgres-auth.enc.yaml
```
# Decrypting
To decrypt a Kubernetes `v1/Secret` encrypted with sops, using `ksops`:
```yaml
# secret.enc.yaml
apiVersion: v1
kind: Secret
metadata:
name: secret-stuff
stringData:
hello: "ENC[AES256_GCM,data:9m+JbWLI=,tag:KTOvMahnDdOnmAEAqzfaMw==,type:str]"
---
# secret-generator.yaml
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
name: ksops
files:
- ./secret.enc.yaml
# kustomization.yaml
generators:
- secret-generator.yaml
```
When running `kustomize`, be sure to pass the `--enable-alpha-plugins` flag.
# Editing
`sops <file>`

20
docs/onboarding.md Normal file
View File

@ -0,0 +1,20 @@
# sops
Add the user to the list of PGP keys in `.sops.yaml`. Run:
```sh
find . -name '*.enc.*' -exec sops updatekeys {} \;
```
# Keycloak
Once authenticated to Keycloak (the password is encrypted in the Keycloak
configuration kustomization), switch from the Master realm to the realm you
wish to add a user to. From there, navigate to Users and select "Add user".
Select a combination of options to be performed upon login, such as "Update
Password" if setting up a user that is not yourself. Enter any necessary
information and select "Create". A temporary password can be generated by using
`pwgen -s 24 1`.
To log in and manage your account, visit the realm login page, such as
https://keycloak.distrust.co/realms/distrust/account.

1
infra/main/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
talos

View File

@ -10,10 +10,23 @@ resource "random_id" "suffix" {
byte_length = 8 byte_length = 8
} }
data "digitalocean_region" "provided" {
slug = var.region
}
resource "digitalocean_custom_image" "talos" { resource "digitalocean_custom_image" "talos" {
name = "talos" name = "talos"
url = "https://github.com/siderolabs/talos/releases/download/v1.2.3/digital-ocean-amd64.raw.gz" url = "https://github.com/siderolabs/talos/releases/download/v1.4.3/digital-ocean-amd64.raw.gz"
regions = ["sfo3"] # this gets reset by DigitalOcean otherwise
distribution = "Unknown OS"
regions = [data.digitalocean_region.provided.slug]
}
resource "digitalocean_vpc" "main" {
name = "talos"
region = data.digitalocean_region.provided.slug
# Note: This is VERY CAREFULLY chosen to avoid conflict with k8s and cilium
ip_range = "192.168.0.0/16"
} }
module "digitalocean_talos_cluster" { module "digitalocean_talos_cluster" {
@ -22,10 +35,82 @@ module "digitalocean_talos_cluster" {
talos_cluster_name = "distrust" talos_cluster_name = "distrust"
talos_image = digitalocean_custom_image.talos.image_id talos_image = digitalocean_custom_image.talos.image_id
talos_config_directory = "talos" talos_config_directory = "talos"
control_plane_pool = {
count = 1,
size = "s-4vcpu-8gb",
}
worker_pools = [{ worker_pools = [{
name = "primary", name = "primary",
count = 1, count = 2,
size = "s-2vcpu-4gb", size = "s-2vcpu-4gb",
}] }]
digitalocean_region = "sfo3" vpc_id = digitalocean_vpc.main.id
digitalocean_region = data.digitalocean_region.provided.slug
}
module "digitalocean_database_cluster" {
source = "../../terraform_modules/digitalocean_database_cluster"
cluster_name = "distrust"
db_engine = "pg"
db_version = "15"
size = "db-s-1vcpu-2gb"
node_count = 1
databases = [{
name = "keycloak",
create_default_superuser = true,
}, {
name = "forgejo",
create_default_superuser = true,
}]
vpc_id = digitalocean_vpc.main.id
digitalocean_region = data.digitalocean_region.provided.slug
}
locals {
database_host = module.digitalocean_database_cluster.database_cluster.private_host
database_port = module.digitalocean_database_cluster.database_cluster.port
database_jdbc_uri_prefix = join("", [
"jdbc:postgresql://",
module.digitalocean_database_cluster.database_cluster.private_host,
":",
module.digitalocean_database_cluster.database_cluster.port,
])
}
# `jq .database_users.value.forgejo | sops --encrypt`
output "database_users" {
value = {
for db_user in module.digitalocean_database_cluster.database_users:
db_user.name => {
apiVersion = "v1",
kind = "Secret",
metadata = {
name = "database-configuration",
},
stringData = {
name = db_user.name,
dbname = db_user.name,
host = local.database_host,
port = tostring(local.database_port),
password = db_user.password,
# Forgejo, they call it "host"
address = join(":", [local.database_host, local.database_port]),
# Keycloak
jdbc_url = "${local.database_jdbc_uri_prefix}/${db_user.name}?sslmode=require",
}
}
}
sensitive = true
}
output "database" {
value = module.digitalocean_database_cluster.database_cluster
sensitive = true
}
output "vpc_id" {
value = digitalocean_vpc.main.id
} }

View File

@ -0,0 +1,16 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: ryan@distrust.co
privateKeySecretRef:
name: letsencrypt
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
digitalocean:
tokenSecretRef:
name: digitalocean
key: access-token

View File

@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- issuer.yaml
generators:
- secret-generator.yaml

View File

@ -0,0 +1,6 @@
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
name: ksops
files:
- ../../digitalocean/digitalocean-config.enc.yaml

View File

@ -0,0 +1,25 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: cert-manager
resources:
- https://github.com/james-callahan/cert-manager-kustomize?ref=b9560b4603bffac901c99d7d9d16e5e2a07e44d8
- cluster-issuer
- namespace.yaml
replacements:
- source:
kind: Deployment
name: cert-manager-webhook
fieldPath: metadata.namespace
targets:
- select:
kind: MutatingWebhookConfiguration
fieldPaths:
- metadata.annotations.[cert-manager.io/inject-ca-from-secret]
options:
delimiter: /
- select:
kind: ValidatingWebhookConfiguration
fieldPaths:
- metadata.annotations.[cert-manager.io/inject-ca-from-secret]
options:
delimiter: /

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager

1
kustomizations/cilium/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
charts

View File

@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
helmCharts:
- name: cilium
repo: https://helm.cilium.io
version: v1.13.2
releaseName: cilium
namespace: kube-system
valuesFile: values.yaml

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
# Secrets
DigitalOcean's CNI and CCM, as well as a few other separate Kustomizations,
require a DigitalOcean token and a VPC id. This can be generated by running:
```sh
sh kustomizations/digitalocean/scripts/generate-digitalocean-token-secret.sh | sops --encrypt --encrypted-regex='^(data|stringData)$' --input-type=yaml --output-type=yaml /dev/stdin > kustomizations/digitalocean/digitalocean-config.enc.yaml
```

View File

@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: digitalocean-cloud-controller-manager
resources:
- resources.yaml
- rbac.yaml

View File

@ -0,0 +1,102 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: cloud-controller-manager
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
name: system:cloud-controller-manager
rules:
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- watch
- list
- create
- update
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- update
- apiGroups:
- ""
resources:
- nodes
verbs:
- '*'
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
- apiGroups:
- ""
resources:
- services
verbs:
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- services/status
verbs:
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
- endpoints
verbs:
- create
- get
- list
- watch
- update
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: system:cloud-controller-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:cloud-controller-manager
subjects:
- kind: ServiceAccount
name: cloud-controller-manager
# NOTE: namespace is replaced using Kustomization.
# This needs to be specified but will be replaced so long as it is 'default'.
namespace: default

View File

@ -0,0 +1,50 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: digitalocean-cloud-controller-manager
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app: digitalocean-cloud-controller-manager
template:
metadata:
labels:
app: digitalocean-cloud-controller-manager
spec:
dnsPolicy: Default
hostNetwork: true
serviceAccountName: cloud-controller-manager
priorityClassName: system-cluster-critical
tolerations:
# this taint is set by all kubelets running `--cloud-provider=external`
# so we should tolerate it to schedule the digitalocean ccm
- key: "node.cloudprovider.kubernetes.io/uninitialized"
value: "true"
effect: "NoSchedule"
- key: "CriticalAddonsOnly"
operator: "Exists"
- key: "node-role.kubernetes.io/control-plane"
effect: NoSchedule
containers:
- image: digitalocean/digitalocean-cloud-controller-manager:v0.1.42
name: digitalocean-cloud-controller-manager
command:
- "/bin/digitalocean-cloud-controller-manager"
- "--leader-elect=false"
resources:
requests:
cpu: 100m
memory: 50Mi
env:
- name: DO_ACCESS_TOKEN
valueFrom:
secretKeyRef:
name: digitalocean
key: access-token
- name: DO_CLUSTER_VPC_ID
valueFrom:
secretKeyRef:
name: digitalocean
key: vpc-id

View File

@ -0,0 +1,865 @@
# Copyright 2022 DigitalOcean
#
# 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.
##############################################
########### ############
########### Snapshot CRDs ############
########### ############
##############################################
#
# Source: https://github.com/kubernetes-csi/external-snapshotter
#
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/665"
creationTimestamp: null
name: volumesnapshotclasses.snapshot.storage.k8s.io
spec:
group: snapshot.storage.k8s.io
names:
kind: VolumeSnapshotClass
listKind: VolumeSnapshotClassList
plural: volumesnapshotclasses
shortNames:
- vsclass
- vsclasses
singular: volumesnapshotclass
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .driver
name: Driver
type: string
- description: Determines whether a VolumeSnapshotContent created through the
VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted.
jsonPath: .deletionPolicy
name: DeletionPolicy
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: VolumeSnapshotClass specifies parameters that a underlying storage
system uses when creating a volume snapshot. A specific VolumeSnapshotClass
is used by specifying its name in a VolumeSnapshot object. VolumeSnapshotClasses
are non-namespaced
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
deletionPolicy:
description: deletionPolicy determines whether a VolumeSnapshotContent
created through the VolumeSnapshotClass should be deleted when its bound
VolumeSnapshot is deleted. Supported values are "Retain" and "Delete".
"Retain" means that the VolumeSnapshotContent and its physical snapshot
on underlying storage system are kept. "Delete" means that the VolumeSnapshotContent
and its physical snapshot on underlying storage system are deleted.
Required.
enum:
- Delete
- Retain
type: string
driver:
description: driver is the name of the storage driver that handles this
VolumeSnapshotClass. Required.
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
parameters:
additionalProperties:
type: string
description: parameters is a key-value map with storage driver specific
parameters for creating snapshots. These values are opaque to Kubernetes.
type: object
required:
- deletionPolicy
- driver
type: object
served: true
storage: true
subresources: {}
- additionalPrinterColumns:
- jsonPath: .driver
name: Driver
type: string
- description: Determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted.
jsonPath: .deletionPolicy
name: DeletionPolicy
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1beta1
# This indicates the v1beta1 version of the custom resource is deprecated.
# API requests to this version receive a warning in the server response.
deprecated: true
# This overrides the default warning returned to clients making v1beta1 API requests.
deprecationWarning: "snapshot.storage.k8s.io/v1beta1 VolumeSnapshotClass is deprecated; use snapshot.storage.k8s.io/v1 VolumeSnapshotClass"
schema:
openAPIV3Schema:
description: VolumeSnapshotClass specifies parameters that a underlying storage system uses when creating a volume snapshot. A specific VolumeSnapshotClass is used by specifying its name in a VolumeSnapshot object. VolumeSnapshotClasses are non-namespaced
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
deletionPolicy:
description: deletionPolicy determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted. Supported values are "Retain" and "Delete". "Retain" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are kept. "Delete" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are deleted. Required.
enum:
- Delete
- Retain
type: string
driver:
description: driver is the name of the storage driver that handles this VolumeSnapshotClass. Required.
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
parameters:
additionalProperties:
type: string
description: parameters is a key-value map with storage driver specific parameters for creating snapshots. These values are opaque to Kubernetes.
type: object
required:
- deletionPolicy
- driver
type: object
served: false
storage: false
subresources: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/665"
creationTimestamp: null
name: volumesnapshotcontents.snapshot.storage.k8s.io
spec:
group: snapshot.storage.k8s.io
names:
kind: VolumeSnapshotContent
listKind: VolumeSnapshotContentList
plural: volumesnapshotcontents
shortNames:
- vsc
- vscs
singular: volumesnapshotcontent
scope: Cluster
versions:
- additionalPrinterColumns:
- description: Indicates if the snapshot is ready to be used to restore a volume.
jsonPath: .status.readyToUse
name: ReadyToUse
type: boolean
- description: Represents the complete size of the snapshot in bytes
jsonPath: .status.restoreSize
name: RestoreSize
type: integer
- description: Determines whether this VolumeSnapshotContent and its physical
snapshot on the underlying storage system should be deleted when its bound
VolumeSnapshot is deleted.
jsonPath: .spec.deletionPolicy
name: DeletionPolicy
type: string
- description: Name of the CSI driver used to create the physical snapshot on
the underlying storage system.
jsonPath: .spec.driver
name: Driver
type: string
- description: Name of the VolumeSnapshotClass to which this snapshot belongs.
jsonPath: .spec.volumeSnapshotClassName
name: VolumeSnapshotClass
type: string
- description: Name of the VolumeSnapshot object to which this VolumeSnapshotContent
object is bound.
jsonPath: .spec.volumeSnapshotRef.name
name: VolumeSnapshot
type: string
- description: Namespace of the VolumeSnapshot object to which this VolumeSnapshotContent object is bound.
jsonPath: .spec.volumeSnapshotRef.namespace
name: VolumeSnapshotNamespace
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: VolumeSnapshotContent represents the actual "on-disk" snapshot
object in the underlying storage system
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
spec:
description: spec defines properties of a VolumeSnapshotContent created
by the underlying storage system. Required.
properties:
deletionPolicy:
description: deletionPolicy determines whether this VolumeSnapshotContent
and its physical snapshot on the underlying storage system should
be deleted when its bound VolumeSnapshot is deleted. Supported values
are "Retain" and "Delete". "Retain" means that the VolumeSnapshotContent
and its physical snapshot on underlying storage system are kept.
"Delete" means that the VolumeSnapshotContent and its physical snapshot
on underlying storage system are deleted. For dynamically provisioned
snapshots, this field will automatically be filled in by the CSI
snapshotter sidecar with the "DeletionPolicy" field defined in the
corresponding VolumeSnapshotClass. For pre-existing snapshots, users
MUST specify this field when creating the VolumeSnapshotContent
object. Required.
enum:
- Delete
- Retain
type: string
driver:
description: driver is the name of the CSI driver used to create the
physical snapshot on the underlying storage system. This MUST be
the same as the name returned by the CSI GetPluginName() call for
that driver. Required.
type: string
source:
description: source specifies whether the snapshot is (or should be)
dynamically provisioned or already exists, and just requires a Kubernetes
object representation. This field is immutable after creation. Required.
properties:
snapshotHandle:
description: snapshotHandle specifies the CSI "snapshot_id" of
a pre-existing snapshot on the underlying storage system for
which a Kubernetes object representation was (or should be)
created. This field is immutable.
type: string
volumeHandle:
description: volumeHandle specifies the CSI "volume_id" of the
volume from which a snapshot should be dynamically taken from.
This field is immutable.
type: string
type: object
oneOf:
- required: ["snapshotHandle"]
- required: ["volumeHandle"]
sourceVolumeMode:
description: SourceVolumeMode is the mode of the volume whose snapshot
is taken. Can be either “Filesystem” or “Block”. If not specified,
it indicates the source volume's mode is unknown. This field is
immutable. This field is an alpha field.
type: string
volumeSnapshotClassName:
description: name of the VolumeSnapshotClass from which this snapshot
was (or will be) created. Note that after provisioning, the VolumeSnapshotClass
may be deleted or recreated with different set of values, and as
such, should not be referenced post-snapshot creation.
type: string
volumeSnapshotRef:
description: volumeSnapshotRef specifies the VolumeSnapshot object
to which this VolumeSnapshotContent object is bound. VolumeSnapshot.Spec.VolumeSnapshotContentName
field must reference to this VolumeSnapshotContent's name for the
bidirectional binding to be valid. For a pre-existing VolumeSnapshotContent
object, name and namespace of the VolumeSnapshot object MUST be
provided for binding to happen. This field is immutable after creation.
Required.
properties:
apiVersion:
description: API version of the referent.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
an entire object, this string should contain a valid JSON/Go
field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within
a pod, this would take on a value like: "spec.containers{name}"
(where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]"
(container with index 2 in this pod). This syntax is chosen
only to have some well-defined way of referencing a part of
an object. TODO: this design is not final and this field is
subject to change in the future.'
type: string
kind:
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
namespace:
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
type: string
resourceVersion:
description: 'Specific resourceVersion to which this reference
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
type: string
uid:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
required:
- deletionPolicy
- driver
- source
- volumeSnapshotRef
type: object
status:
description: status represents the current information of a snapshot.
properties:
creationTime:
description: creationTime is the timestamp when the point-in-time
snapshot is taken by the underlying storage system. In dynamic snapshot
creation case, this field will be filled in by the CSI snapshotter
sidecar with the "creation_time" value returned from CSI "CreateSnapshot"
gRPC call. For a pre-existing snapshot, this field will be filled
with the "creation_time" value returned from the CSI "ListSnapshots"
gRPC call if the driver supports it. If not specified, it indicates
the creation time is unknown. The format of this field is a Unix
nanoseconds time encoded as an int64. On Unix, the command `date
+%s%N` returns the current time in nanoseconds since 1970-01-01
00:00:00 UTC.
format: int64
type: integer
error:
description: error is the last observed error during snapshot creation,
if any. Upon success after retry, this error field will be cleared.
properties:
message:
description: 'message is a string detailing the encountered error
during snapshot creation if specified. NOTE: message may be
logged, and it should not contain sensitive information.'
type: string
time:
description: time is the timestamp when the error was encountered.
format: date-time
type: string
type: object
readyToUse:
description: readyToUse indicates if a snapshot is ready to be used
to restore a volume. In dynamic snapshot creation case, this field
will be filled in by the CSI snapshotter sidecar with the "ready_to_use"
value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing
snapshot, this field will be filled with the "ready_to_use" value
returned from the CSI "ListSnapshots" gRPC call if the driver supports
it, otherwise, this field will be set to "True". If not specified,
it means the readiness of a snapshot is unknown.
type: boolean
restoreSize:
description: restoreSize represents the complete size of the snapshot
in bytes. In dynamic snapshot creation case, this field will be
filled in by the CSI snapshotter sidecar with the "size_bytes" value
returned from CSI "CreateSnapshot" gRPC call. For a pre-existing
snapshot, this field will be filled with the "size_bytes" value
returned from the CSI "ListSnapshots" gRPC call if the driver supports
it. When restoring a volume from this snapshot, the size of the
volume MUST NOT be smaller than the restoreSize if it is specified,
otherwise the restoration will fail. If not specified, it indicates
that the size is unknown.
format: int64
minimum: 0
type: integer
snapshotHandle:
description: snapshotHandle is the CSI "snapshot_id" of a snapshot
on the underlying storage system. If not specified, it indicates
that dynamic snapshot creation has either failed or it is still
in progress.
type: string
type: object
required:
- spec
type: object
served: true
storage: true
subresources:
status: {}
- additionalPrinterColumns:
- description: Indicates if the snapshot is ready to be used to restore a volume.
jsonPath: .status.readyToUse
name: ReadyToUse
type: boolean
- description: Represents the complete size of the snapshot in bytes
jsonPath: .status.restoreSize
name: RestoreSize
type: integer
- description: Determines whether this VolumeSnapshotContent and its physical snapshot on the underlying storage system should be deleted when its bound VolumeSnapshot is deleted.
jsonPath: .spec.deletionPolicy
name: DeletionPolicy
type: string
- description: Name of the CSI driver used to create the physical snapshot on the underlying storage system.
jsonPath: .spec.driver
name: Driver
type: string
- description: Name of the VolumeSnapshotClass to which this snapshot belongs.
jsonPath: .spec.volumeSnapshotClassName
name: VolumeSnapshotClass
type: string
- description: Name of the VolumeSnapshot object to which this VolumeSnapshotContent object is bound.
jsonPath: .spec.volumeSnapshotRef.name
name: VolumeSnapshot
type: string
- description: Namespace of the VolumeSnapshot object to which this VolumeSnapshotContent object is bound.
jsonPath: .spec.volumeSnapshotRef.namespace
name: VolumeSnapshotNamespace
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1beta1
# This indicates the v1beta1 version of the custom resource is deprecated.
# API requests to this version receive a warning in the server response.
deprecated: true
# This overrides the default warning returned to clients making v1beta1 API requests.
deprecationWarning: "snapshot.storage.k8s.io/v1beta1 VolumeSnapshotContent is deprecated; use snapshot.storage.k8s.io/v1 VolumeSnapshotContent"
schema:
openAPIV3Schema:
description: VolumeSnapshotContent represents the actual "on-disk" snapshot object in the underlying storage system
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
spec:
description: spec defines properties of a VolumeSnapshotContent created by the underlying storage system. Required.
properties:
deletionPolicy:
description: deletionPolicy determines whether this VolumeSnapshotContent and its physical snapshot on the underlying storage system should be deleted when its bound VolumeSnapshot is deleted. Supported values are "Retain" and "Delete". "Retain" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are kept. "Delete" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are deleted. For dynamically provisioned snapshots, this field will automatically be filled in by the CSI snapshotter sidecar with the "DeletionPolicy" field defined in the corresponding VolumeSnapshotClass. For pre-existing snapshots, users MUST specify this field when creating the VolumeSnapshotContent object. Required.
enum:
- Delete
- Retain
type: string
driver:
description: driver is the name of the CSI driver used to create the physical snapshot on the underlying storage system. This MUST be the same as the name returned by the CSI GetPluginName() call for that driver. Required.
type: string
source:
description: source specifies whether the snapshot is (or should be) dynamically provisioned or already exists, and just requires a Kubernetes object representation. This field is immutable after creation. Required.
properties:
snapshotHandle:
description: snapshotHandle specifies the CSI "snapshot_id" of a pre-existing snapshot on the underlying storage system for which a Kubernetes object representation was (or should be) created. This field is immutable.
type: string
volumeHandle:
description: volumeHandle specifies the CSI "volume_id" of the volume from which a snapshot should be dynamically taken from. This field is immutable.
type: string
type: object
volumeSnapshotClassName:
description: name of the VolumeSnapshotClass from which this snapshot was (or will be) created. Note that after provisioning, the VolumeSnapshotClass may be deleted or recreated with different set of values, and as such, should not be referenced post-snapshot creation.
type: string
volumeSnapshotRef:
description: volumeSnapshotRef specifies the VolumeSnapshot object to which this VolumeSnapshotContent object is bound. VolumeSnapshot.Spec.VolumeSnapshotContentName field must reference to this VolumeSnapshotContent's name for the bidirectional binding to be valid. For a pre-existing VolumeSnapshotContent object, name and namespace of the VolumeSnapshot object MUST be provided for binding to happen. This field is immutable after creation. Required.
properties:
apiVersion:
description: API version of the referent.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.'
type: string
kind:
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
namespace:
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
type: string
resourceVersion:
description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
type: string
uid:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
required:
- deletionPolicy
- driver
- source
- volumeSnapshotRef
type: object
status:
description: status represents the current information of a snapshot.
properties:
creationTime:
description: creationTime is the timestamp when the point-in-time snapshot is taken by the underlying storage system. In dynamic snapshot creation case, this field will be filled in by the CSI snapshotter sidecar with the "creation_time" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "creation_time" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. If not specified, it indicates the creation time is unknown. The format of this field is a Unix nanoseconds time encoded as an int64. On Unix, the command `date +%s%N` returns the current time in nanoseconds since 1970-01-01 00:00:00 UTC.
format: int64
type: integer
error:
description: error is the last observed error during snapshot creation, if any. Upon success after retry, this error field will be cleared.
properties:
message:
description: 'message is a string detailing the encountered error during snapshot creation if specified. NOTE: message may be logged, and it should not contain sensitive information.'
type: string
time:
description: time is the timestamp when the error was encountered.
format: date-time
type: string
type: object
readyToUse:
description: readyToUse indicates if a snapshot is ready to be used to restore a volume. In dynamic snapshot creation case, this field will be filled in by the CSI snapshotter sidecar with the "ready_to_use" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "ready_to_use" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it, otherwise, this field will be set to "True". If not specified, it means the readiness of a snapshot is unknown.
type: boolean
restoreSize:
description: restoreSize represents the complete size of the snapshot in bytes. In dynamic snapshot creation case, this field will be filled in by the CSI snapshotter sidecar with the "size_bytes" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "size_bytes" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. When restoring a volume from this snapshot, the size of the volume MUST NOT be smaller than the restoreSize if it is specified, otherwise the restoration will fail. If not specified, it indicates that the size is unknown.
format: int64
minimum: 0
type: integer
snapshotHandle:
description: snapshotHandle is the CSI "snapshot_id" of a snapshot on the underlying storage system. If not specified, it indicates that dynamic snapshot creation has either failed or it is still in progress.
type: string
type: object
required:
- spec
type: object
served: false
storage: false
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/665"
creationTimestamp: null
name: volumesnapshots.snapshot.storage.k8s.io
spec:
group: snapshot.storage.k8s.io
names:
kind: VolumeSnapshot
listKind: VolumeSnapshotList
plural: volumesnapshots
shortNames:
- vs
singular: volumesnapshot
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: Indicates if the snapshot is ready to be used to restore a volume.
jsonPath: .status.readyToUse
name: ReadyToUse
type: boolean
- description: If a new snapshot needs to be created, this contains the name of
the source PVC from which this snapshot was (or will be) created.
jsonPath: .spec.source.persistentVolumeClaimName
name: SourcePVC
type: string
- description: If a snapshot already exists, this contains the name of the existing
VolumeSnapshotContent object representing the existing snapshot.
jsonPath: .spec.source.volumeSnapshotContentName
name: SourceSnapshotContent
type: string
- description: Represents the minimum size of volume required to rehydrate from
this snapshot.
jsonPath: .status.restoreSize
name: RestoreSize
type: string
- description: The name of the VolumeSnapshotClass requested by the VolumeSnapshot.
jsonPath: .spec.volumeSnapshotClassName
name: SnapshotClass
type: string
- description: Name of the VolumeSnapshotContent object to which the VolumeSnapshot
object intends to bind to. Please note that verification of binding actually
requires checking both VolumeSnapshot and VolumeSnapshotContent to ensure
both are pointing at each other. Binding MUST be verified prior to usage of
this object.
jsonPath: .status.boundVolumeSnapshotContentName
name: SnapshotContent
type: string
- description: Timestamp when the point-in-time snapshot was taken by the underlying
storage system.
jsonPath: .status.creationTime
name: CreationTime
type: date
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: VolumeSnapshot is a user's request for either creating a point-in-time
snapshot of a persistent volume, or binding to a pre-existing snapshot.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
spec:
description: 'spec defines the desired characteristics of a snapshot requested
by a user. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots
Required.'
properties:
source:
description: source specifies where a snapshot will be created from.
This field is immutable after creation. Required.
properties:
persistentVolumeClaimName:
description: persistentVolumeClaimName specifies the name of the
PersistentVolumeClaim object representing the volume from which
a snapshot should be created. This PVC is assumed to be in the
same namespace as the VolumeSnapshot object. This field should
be set if the snapshot does not exists, and needs to be created.
This field is immutable.
type: string
volumeSnapshotContentName:
description: volumeSnapshotContentName specifies the name of a
pre-existing VolumeSnapshotContent object representing an existing
volume snapshot. This field should be set if the snapshot already
exists and only needs a representation in Kubernetes. This field
is immutable.
type: string
type: object
oneOf:
- required: ["persistentVolumeClaimName"]
- required: ["volumeSnapshotContentName"]
volumeSnapshotClassName:
description: 'VolumeSnapshotClassName is the name of the VolumeSnapshotClass
requested by the VolumeSnapshot. VolumeSnapshotClassName may be
left nil to indicate that the default SnapshotClass should be used.
A given cluster may have multiple default Volume SnapshotClasses:
one default per CSI Driver. If a VolumeSnapshot does not specify
a SnapshotClass, VolumeSnapshotSource will be checked to figure
out what the associated CSI Driver is, and the default VolumeSnapshotClass
associated with that CSI Driver will be used. If more than one VolumeSnapshotClass
exist for a given CSI Driver and more than one have been marked
as default, CreateSnapshot will fail and generate an event. Empty
string is not allowed for this field.'
type: string
required:
- source
type: object
status:
description: status represents the current information of a snapshot.
Consumers must verify binding between VolumeSnapshot and VolumeSnapshotContent
objects is successful (by validating that both VolumeSnapshot and VolumeSnapshotContent
point at each other) before using this object.
properties:
boundVolumeSnapshotContentName:
description: 'boundVolumeSnapshotContentName is the name of the VolumeSnapshotContent
object to which this VolumeSnapshot object intends to bind to. If
not specified, it indicates that the VolumeSnapshot object has not
been successfully bound to a VolumeSnapshotContent object yet. NOTE:
To avoid possible security issues, consumers must verify binding
between VolumeSnapshot and VolumeSnapshotContent objects is successful
(by validating that both VolumeSnapshot and VolumeSnapshotContent
point at each other) before using this object.'
type: string
creationTime:
description: creationTime is the timestamp when the point-in-time
snapshot is taken by the underlying storage system. In dynamic snapshot
creation case, this field will be filled in by the snapshot controller
with the "creation_time" value returned from CSI "CreateSnapshot"
gRPC call. For a pre-existing snapshot, this field will be filled
with the "creation_time" value returned from the CSI "ListSnapshots"
gRPC call if the driver supports it. If not specified, it may indicate
that the creation time of the snapshot is unknown.
format: date-time
type: string
error:
description: error is the last observed error during snapshot creation,
if any. This field could be helpful to upper level controllers(i.e.,
application controller) to decide whether they should continue on
waiting for the snapshot to be created based on the type of error
reported. The snapshot controller will keep retrying when an error
occurs during the snapshot creation. Upon success, this error field
will be cleared.
properties:
message:
description: 'message is a string detailing the encountered error
during snapshot creation if specified. NOTE: message may be
logged, and it should not contain sensitive information.'
type: string
time:
description: time is the timestamp when the error was encountered.
format: date-time
type: string
type: object
readyToUse:
description: readyToUse indicates if the snapshot is ready to be used
to restore a volume. In dynamic snapshot creation case, this field
will be filled in by the snapshot controller with the "ready_to_use"
value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing
snapshot, this field will be filled with the "ready_to_use" value
returned from the CSI "ListSnapshots" gRPC call if the driver supports
it, otherwise, this field will be set to "True". If not specified,
it means the readiness of a snapshot is unknown.
type: boolean
restoreSize:
type: string
description: restoreSize represents the minimum size of volume required
to create a volume from this snapshot. In dynamic snapshot creation
case, this field will be filled in by the snapshot controller with
the "size_bytes" value returned from CSI "CreateSnapshot" gRPC call.
For a pre-existing snapshot, this field will be filled with the
"size_bytes" value returned from the CSI "ListSnapshots" gRPC call
if the driver supports it. When restoring a volume from this snapshot,
the size of the volume MUST NOT be smaller than the restoreSize
if it is specified, otherwise the restoration will fail. If not
specified, it indicates that the size is unknown.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
type: object
required:
- spec
type: object
served: true
storage: true
subresources:
status: {}
- additionalPrinterColumns:
- description: Indicates if the snapshot is ready to be used to restore a volume.
jsonPath: .status.readyToUse
name: ReadyToUse
type: boolean
- description: If a new snapshot needs to be created, this contains the name of the source PVC from which this snapshot was (or will be) created.
jsonPath: .spec.source.persistentVolumeClaimName
name: SourcePVC
type: string
- description: If a snapshot already exists, this contains the name of the existing VolumeSnapshotContent object representing the existing snapshot.
jsonPath: .spec.source.volumeSnapshotContentName
name: SourceSnapshotContent
type: string
- description: Represents the minimum size of volume required to rehydrate from this snapshot.
jsonPath: .status.restoreSize
name: RestoreSize
type: string
- description: The name of the VolumeSnapshotClass requested by the VolumeSnapshot.
jsonPath: .spec.volumeSnapshotClassName
name: SnapshotClass
type: string
- description: Name of the VolumeSnapshotContent object to which the VolumeSnapshot object intends to bind to. Please note that verification of binding actually requires checking both VolumeSnapshot and VolumeSnapshotContent to ensure both are pointing at each other. Binding MUST be verified prior to usage of this object.
jsonPath: .status.boundVolumeSnapshotContentName
name: SnapshotContent
type: string
- description: Timestamp when the point-in-time snapshot was taken by the underlying storage system.
jsonPath: .status.creationTime
name: CreationTime
type: date
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1beta1
# This indicates the v1beta1 version of the custom resource is deprecated.
# API requests to this version receive a warning in the server response.
deprecated: true
# This overrides the default warning returned to clients making v1beta1 API requests.
deprecationWarning: "snapshot.storage.k8s.io/v1beta1 VolumeSnapshot is deprecated; use snapshot.storage.k8s.io/v1 VolumeSnapshot"
schema:
openAPIV3Schema:
description: VolumeSnapshot is a user's request for either creating a point-in-time snapshot of a persistent volume, or binding to a pre-existing snapshot.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
spec:
description: 'spec defines the desired characteristics of a snapshot requested by a user. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots Required.'
properties:
source:
description: source specifies where a snapshot will be created from. This field is immutable after creation. Required.
properties:
persistentVolumeClaimName:
description: persistentVolumeClaimName specifies the name of the PersistentVolumeClaim object representing the volume from which a snapshot should be created. This PVC is assumed to be in the same namespace as the VolumeSnapshot object. This field should be set if the snapshot does not exists, and needs to be created. This field is immutable.
type: string
volumeSnapshotContentName:
description: volumeSnapshotContentName specifies the name of a pre-existing VolumeSnapshotContent object representing an existing volume snapshot. This field should be set if the snapshot already exists and only needs a representation in Kubernetes. This field is immutable.
type: string
type: object
volumeSnapshotClassName:
description: 'VolumeSnapshotClassName is the name of the VolumeSnapshotClass requested by the VolumeSnapshot. VolumeSnapshotClassName may be left nil to indicate that the default SnapshotClass should be used. A given cluster may have multiple default Volume SnapshotClasses: one default per CSI Driver. If a VolumeSnapshot does not specify a SnapshotClass, VolumeSnapshotSource will be checked to figure out what the associated CSI Driver is, and the default VolumeSnapshotClass associated with that CSI Driver will be used. If more than one VolumeSnapshotClass exist for a given CSI Driver and more than one have been marked as default, CreateSnapshot will fail and generate an event. Empty string is not allowed for this field.'
type: string
required:
- source
type: object
status:
description: status represents the current information of a snapshot. Consumers must verify binding between VolumeSnapshot and VolumeSnapshotContent objects is successful (by validating that both VolumeSnapshot and VolumeSnapshotContent point at each other) before using this object.
properties:
boundVolumeSnapshotContentName:
description: 'boundVolumeSnapshotContentName is the name of the VolumeSnapshotContent object to which this VolumeSnapshot object intends to bind to. If not specified, it indicates that the VolumeSnapshot object has not been successfully bound to a VolumeSnapshotContent object yet. NOTE: To avoid possible security issues, consumers must verify binding between VolumeSnapshot and VolumeSnapshotContent objects is successful (by validating that both VolumeSnapshot and VolumeSnapshotContent point at each other) before using this object.'
type: string
creationTime:
description: creationTime is the timestamp when the point-in-time snapshot is taken by the underlying storage system. In dynamic snapshot creation case, this field will be filled in by the snapshot controller with the "creation_time" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "creation_time" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. If not specified, it may indicate that the creation time of the snapshot is unknown.
format: date-time
type: string
error:
description: error is the last observed error during snapshot creation, if any. This field could be helpful to upper level controllers(i.e., application controller) to decide whether they should continue on waiting for the snapshot to be created based on the type of error reported. The snapshot controller will keep retrying when an error occurs during the snapshot creation. Upon success, this error field will be cleared.
properties:
message:
description: 'message is a string detailing the encountered error during snapshot creation if specified. NOTE: message may be logged, and it should not contain sensitive information.'
type: string
time:
description: time is the timestamp when the error was encountered.
format: date-time
type: string
type: object
readyToUse:
description: readyToUse indicates if the snapshot is ready to be used to restore a volume. In dynamic snapshot creation case, this field will be filled in by the snapshot controller with the "ready_to_use" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "ready_to_use" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it, otherwise, this field will be set to "True". If not specified, it means the readiness of a snapshot is unknown.
type: boolean
restoreSize:
type: string
description: restoreSize represents the minimum size of volume required to create a volume from this snapshot. In dynamic snapshot creation case, this field will be filled in by the snapshot controller with the "size_bytes" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "size_bytes" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. When restoring a volume from this snapshot, the size of the volume MUST NOT be smaller than the restoreSize if it is specified, otherwise the restoration will fail. If not specified, it indicates that the size is unknown.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
type: object
required:
- spec
type: object
served: false
storage: false
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -0,0 +1,503 @@
# Copyright 2022 DigitalOcean
#
# 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.
# Install the CSI Driver. This simplifies driver discovery and enables us to
# customize Kubernetes behavior
# https://kubernetes-csi.github.io/docs/csi-driver-object.html
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: dobs.csi.digitalocean.com
spec:
attachRequired: true
podInfoOnMount: true
---
kind: VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
metadata:
name: do-block-storage
annotations:
snapshot.storage.kubernetes.io/is-default-class: "true"
driver: dobs.csi.digitalocean.com
deletionPolicy: Delete
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: do-block-storage
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: dobs.csi.digitalocean.com
reclaimPolicy: Retain
allowVolumeExpansion: true
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: do-block-storage-ephemeral
provisioner: dobs.csi.digitalocean.com
reclaimPolicy: Delete
allowVolumeExpansion: true
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: do-block-storage-xfs
provisioner: dobs.csi.digitalocean.com
parameters:
fstype: xfs
reclaimPolicy: Retain
allowVolumeExpansion: true
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: do-block-storage-xfs-ephemeral
provisioner: dobs.csi.digitalocean.com
parameters:
fstype: xfs
reclaimPolicy: Delete
allowVolumeExpansion: true
---
##############################################
########### ############
########### Controller plugin ############
########### ############
##############################################
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: csi-do-controller
namespace: kube-system
spec:
serviceName: "csi-do"
selector:
matchLabels:
app: csi-do-controller
replicas: 1
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: csi-do-plugin
labels:
app: csi-do-controller
role: csi-do
spec:
priorityClassName: system-cluster-critical
serviceAccount: csi-do-controller-sa
containers:
- name: csi-provisioner
image: registry.k8s.io/sig-storage/csi-provisioner:v3.3.0
args:
- "--csi-address=$(ADDRESS)"
- "--default-fstype=ext4"
- "--v=5"
env:
- name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
- name: csi-attacher
image: registry.k8s.io/sig-storage/csi-attacher:v4.0.0
args:
- "--csi-address=$(ADDRESS)"
- "--v=5"
- "--reconcile-sync=30m"
- "--timeout=2m"
env:
- name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
- name: csi-snapshotter
image: registry.k8s.io/sig-storage/csi-snapshotter:v6.1.0
args:
- "--csi-address=$(ADDRESS)"
- "--v=5"
env:
- name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock
imagePullPolicy: IfNotPresent
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
- name: csi-resizer
image: registry.k8s.io/sig-storage/csi-resizer:v1.6.0
args:
- "--csi-address=$(ADDRESS)"
- "--timeout=30s"
- "--v=5"
# DO volumes support online resize.
- "--handle-volume-inuse-error=false"
env:
- name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
- name: csi-do-plugin
image: digitalocean/do-csi-plugin:v4.4.1
args :
- "--endpoint=$(CSI_ENDPOINT)"
- "--token=$(DIGITALOCEAN_ACCESS_TOKEN)"
- "--url=$(DIGITALOCEAN_API_URL)"
- "--default-volumes-page-size=200"
env:
- name: CSI_ENDPOINT
value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock
- name: DIGITALOCEAN_API_URL
value: https://api.digitalocean.com/
- name: DIGITALOCEAN_ACCESS_TOKEN
valueFrom:
secretKeyRef:
name: digitalocean
key: access-token
imagePullPolicy: "Always"
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
volumes:
- name: socket-dir
emptyDir: {}
---
kind: ServiceAccount
apiVersion: v1
metadata:
name: csi-do-controller-sa
namespace: kube-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-provisioner-role
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshots"]
verbs: ["get", "list"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotcontents"]
verbs: ["get", "list"]
- apiGroups: [ "storage.k8s.io" ]
resources: [ "csinodes" ]
verbs: [ "get", "list", "watch" ]
- apiGroups: [ "" ]
resources: [ "nodes" ]
verbs: [ "get", "list", "watch" ]
- apiGroups: ["storage.k8s.io"]
resources: ["volumeattachments"]
verbs: ["get", "list", "watch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-provisioner-binding
subjects:
- kind: ServiceAccount
name: csi-do-controller-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: csi-do-provisioner-role
apiGroup: rbac.authorization.k8s.io
---
# Attacher must be able to work with PVs, nodes and VolumeAttachments
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-attacher-role
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: ["storage.k8s.io"]
resources: ["csinodes"]
verbs: ["get", "list", "watch"]
- apiGroups: ["storage.k8s.io"]
resources: ["volumeattachments"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: ["storage.k8s.io"]
resources: ["volumeattachments/status"]
verbs: ["patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-attacher-binding
subjects:
- kind: ServiceAccount
name: csi-do-controller-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: csi-do-attacher-role
apiGroup: rbac.authorization.k8s.io
---
# Snapshotter sidecar
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-snapshotter-role
rules:
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotcontents"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotcontents/status"]
verbs: ["update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-snapshotter-binding
subjects:
- kind: ServiceAccount
name: csi-do-controller-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: csi-do-snapshotter-role
apiGroup: rbac.authorization.k8s.io
---
# Resizer must be able to work with PVCs, PVs, SCs.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-resizer-role
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumeclaims/status"]
verbs: ["update", "patch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-resizer-binding
subjects:
- kind: ServiceAccount
name: csi-do-controller-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: csi-do-resizer-role
apiGroup: rbac.authorization.k8s.io
---
########################################
########### ############
########### Node plugin ############
########### ############
########################################
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: csi-do-node
namespace: kube-system
spec:
selector:
matchLabels:
app: csi-do-node
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: csi-do-plugin
labels:
app: csi-do-node
role: csi-do
spec:
priorityClassName: system-node-critical
serviceAccount: csi-do-node-sa
hostNetwork: true
initContainers:
# Delete automount udev rule running on all DO droplets. The rule mounts
# devices briefly and may conflict with CSI-managed droplets (leading to
# "resource busy" errors). We can safely delete it in DOKS.
# - name: automount-udev-deleter
# image: alpine:3
# args:
# - "rm"
# - "-f"
# - "/etc/udev/rules.d/99-digitalocean-automount.rules"
# volumeMounts:
# - name: udev-rules-dir
# mountPath: /etc/udev/rules.d/
containers:
- name: csi-node-driver-registrar
image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.6.0
args:
- "--v=5"
- "--csi-address=$(ADDRESS)"
- "--kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)"
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "rm -rf /registration/dobs.csi.digitalocean.com /registration/dobs.csi.digitalocean.com-reg.sock"]
env:
- name: ADDRESS
value: /csi/csi.sock
- name: DRIVER_REG_SOCK_PATH
value: /var/lib/kubelet/plugins/dobs.csi.digitalocean.com/csi.sock
- name: KUBE_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- name: plugin-dir
mountPath: /csi/
- name: registration-dir
mountPath: /registration/
- name: csi-do-plugin
image: digitalocean/do-csi-plugin:v4.4.1
args :
- "--endpoint=$(CSI_ENDPOINT)"
- "--url=$(DIGITALOCEAN_API_URL)"
env:
- name: CSI_ENDPOINT
value: unix:///csi/csi.sock
- name: DIGITALOCEAN_API_URL
value: https://api.digitalocean.com/
imagePullPolicy: "Always"
securityContext:
privileged: true
capabilities:
add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true
volumeMounts:
- name: plugin-dir
mountPath: /csi
- name: pods-mount-dir
mountPath: /var/lib/kubelet
# needed so that any mounts setup inside this container are
# propagated back to the host machine.
mountPropagation: "Bidirectional"
- name: device-dir
mountPath: /dev
volumes:
- name: registration-dir
hostPath:
path: /var/lib/kubelet/plugins_registry/
type: DirectoryOrCreate
- name: plugin-dir
hostPath:
path: /var/lib/kubelet/plugins/dobs.csi.digitalocean.com
type: DirectoryOrCreate
- name: pods-mount-dir
hostPath:
path: /var/lib/kubelet
type: Directory
- name: device-dir
hostPath:
path: /dev
# - name: udev-rules-dir
# hostPath:
# path: /etc/udev/rules.d/
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: csi-do-node-sa
namespace: kube-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-node-driver-registrar-role
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-do-node-driver-registrar-binding
subjects:
- kind: ServiceAccount
name: csi-do-node-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: csi-do-node-driver-registrar-role
apiGroup: rbac.authorization.k8s.io

View File

@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: digitalocean-csi
resources:
- driver.yaml
- crds.yaml
- snapshot-controller.yaml
images:
- name: k8s.gcr.io/sig-storage/snapshot-validation-webhook:v6.0.1
digest: sha256:4561bb8ac0e826cfecf5b2859ee50f7075916c772d4235bad528fc4be616a0cb
- name: k8s.gcr.io/sig-storage/snapshot-controller:v6.0.1
digest: sha256:a49993c3325b4bb010e52b8e661ebc62b9d45ebceae6e432d3ee637a4833bae7
- name: k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.5.1
digest: sha256:0103eee7c35e3e0b5cd8cdca9850dc71c793cdeb6669d8be7a89440da2d06ae4

View File

@ -0,0 +1,98 @@
# Copyright 2022 DigitalOcean
#
# 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.
#
# snapshotter controller
# source: # Source: https://github.com/kubernetes-csi/external-snapshotter
#
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: snapshot-controller
namespace: kube-system
spec:
serviceName: "snapshot-controller"
replicas: 1
selector:
matchLabels:
app: snapshot-controller
template:
metadata:
labels:
app: snapshot-controller
spec:
serviceAccountName: snapshot-controller
containers:
- name: snapshot-controller
image: registry.k8s.io/sig-storage/snapshot-controller:v6.1.0
args:
- "--v=5"
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: snapshot-controller
namespace: kube-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: snapshot-controller-role
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotcontents"]
verbs: ["create", "get", "list", "watch", "update", "delete", "patch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotcontents/status"]
verbs: ["patch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshots"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshots/status"]
verbs: ["update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: snapshot-controller-binding
subjects:
- kind: ServiceAccount
name: snapshot-controller
namespace: kube-system
roleRef:
kind: ClusterRole
name: snapshot-controller-role
apiGroup: rbac.authorization.k8s.io

View File

@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- resources.yaml

View File

@ -0,0 +1,7 @@
nameReference:
- kind: Issuer
group: cert-manager.io
fieldSpecs:
- kind: Certificate
group: cert-manager.io
path: spec/issuerRef/name

View File

@ -0,0 +1,148 @@
# Copyright 2022 DigitalOcean
#
# 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.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: "validation-webhook.snapshot.storage.k8s.io"
annotations:
cert-manager.io/inject-ca-from: default/snapshot-validation
webhooks:
- name: "validation-webhook.snapshot.storage.k8s.io"
rules:
- apiGroups: ["snapshot.storage.k8s.io"]
apiVersions: ["v1", "v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["volumesnapshots", "volumesnapshotcontents"]
scope: "*"
clientConfig:
service:
namespace: "kube-system"
name: "snapshot-validation-service"
path: "/volumesnapshot"
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
failurePolicy: Fail
timeoutSeconds: 5
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: snapshot-validation
namespace: kube-system
labels:
app: snapshot-validation
spec:
replicas: 1
selector:
matchLabels:
app: snapshot-validation
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
labels:
app: snapshot-validation
spec:
serviceAccountName: snapshot-validation
containers:
- name: snapshot-validation
image: registry.k8s.io/sig-storage/snapshot-validation-webhook:v6.1.0
imagePullPolicy: IfNotPresent
args: ['--tls-cert-file=/etc/snapshot-validation-webhook/certs/tls.crt', '--tls-private-key-file=/etc/snapshot-validation-webhook/certs/tls.key']
ports:
- containerPort: 443
volumeMounts:
- name: snapshot-validation-webhook-certs
mountPath: /etc/snapshot-validation-webhook/certs
readOnly: true
volumes:
- name: snapshot-validation-webhook-certs
secret:
secretName: snapshot-validation-secret
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: snapshot-validation
namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
name: snapshot-validation-service
namespace: kube-system
spec:
selector:
app: snapshot-validation
ports:
- protocol: TCP
port: 443
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: snapshot-validation
rules:
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshotclasses"]
verbs: ["get", "list", "watch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: snapshot-validation
subjects:
- kind: ServiceAccount
name: snapshot-validation
namespace: kube-system
roleRef:
kind: ClusterRole
name: snapshot-validation
apiGroup: rbac.authorization.k8s.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: snapshot-validation
spec:
dnsNames:
- snapshot-validation-service
- snapshot-validation-service.default.svc
issuerRef:
kind: Issuer
name: selfsigned-issuer
secretName: snapshot-validation-secret

View File

@ -0,0 +1,78 @@
apiVersion: v1
kind: Secret
metadata:
name: digitalocean
stringData:
vpc-id: ENC[AES256_GCM,data:HPnbLIwgO9M0cmaH6X3clW4SrdyjWSL5dNMRKIilFzqvbKh0,iv:uh4YohrDpqO/7sissal5OMhAVeOFX4TFzEbvKzbRjnY=,tag:CjNkUHxY5aYCLQYGp48U8A==,type:str]
access-token: ENC[AES256_GCM,data:iyMUvEppUgrDOJRjeDI87YxhSM7SYTO2znjL9lXjzMDARoc+byAvB1Rml41UCvKcKGNgg7/1Vqx2oLKm7BpgXXIqP3DG8Kk=,iv:gAPwgSYrYJ3bRj0PDoSey2JuOYiAyXaGXK19OpEbAA0=,tag:/dY5NLrq302iHOK1oV3n2w==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-05-17T02:32:42Z"
mac: ENC[AES256_GCM,data:/r3XV5k2UXxRwNv+comZBBSKftovXuhx5opWa6w6u4aM2vfJcjwdAZ/ZvgHpoLJxk3tjm77beCnCMLTmGfL2L2eT/WrBCiZHofXd6bHZQ6t8jNiPz4R2P4E0Cb/O4sSGCw2/TUxyiBlQKNJfVhNPmtfpBrgQ+eXQIuuSM+lr5UM=,iv:krSMU45WsO7Ew/2EmyJUQc9/yH/ejiI0MXdd9kYC7KE=,tag:2kugMJ710d67vO806tzMyw==,type:str]
pgp:
- created_at: "2023-05-17T02:31:40Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA82rPM2mSf/aAQ/8DQLl7JeBVWmGjI79aJ5bDzIxvQ+MJ7GsFdjd1aWc9oM3
pldz7saZVbMtth9AllTQSJHpOQUtrTi7eiGHzGt6M+xYMcaaA6PkNDDQFQ2GF0FG
3zNFeK0k77DcsVlk/T+XPDH9XZkqMzIACQopp43ORyRPS/rTNMHEM7eag5OIQ+6N
seQFkP0fZaSG+Vg3IO5xLFOKE/u/E5P6sk//6hKty6jZcJKU9KeSJu9YrjiDtK3l
uQRcXG3fmWvtjS+2PQ/mN+e4vd+pA08StrHaTHvEbWCp8s/bO7cvISmsGss4byEc
MXvuKNUrzQ4yrHVd9UI19Tmlzat19QwEVoIfgrqbEBElKxdM5hoHRU9kgu+ROICi
rRKGcHLHBOuJKRtd7XGo7sML4WuWJ949uJC4e4LL5MGernUhNXNkcZHvhFktvvUc
bMQ/NzGu3O2m584e4AU7B+o7lZTicYheLi90MewczJx3AThZOjNMS4NVIj0fuSnd
2dtVrnoLwgIvd9aTolI9JSBOWmQpmIHza3goyoGmzcrN6f6Ky0I6Z9P7TQsiu6T1
YYhWmeXrBaJWePhHF860v0UIjYjnhjP89mLgpQkQ/yVQGULYpHhdP2Pm9oAZdaav
J7fJEwCJtw8Jzq+E51f2SDr1yJCqFEb2c1vXIj3edP7LTeXJ6QX7b91W9qr79vXS
UQGt/yauDfM9PyApcHaF7AZeWmAvig/Pmo3fqC95CXQ0zqSIzNxz/k6iFY1q86Mo
1Qu5AHW51xzs5VOwcVnQfw+1AKHZG7pm4LHlEzJDdnqjVA==
=pEDh
-----END PGP MESSAGE-----
fp: 6B61ECD76088748C70590D55E90A401336C8AAA9
- created_at: "2023-05-17T02:31:40Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMAw95Vf08z8oUAQ//avLBHqWsB5wyosA7E2KDadn82k2A0w3Zh8XDxljznwzD
N/PcE4QORIEb1iqlK34T+XqRURUzM4Ct3Sbti/G5IThm4usE9js+wUNXNqMrSPW4
m6dr//5YNHRLMDS0t1MMhhhLY3PWgnx3LSrb7PJhCVo2D0HSgRZDoGZSj6cfLUFl
5FKeIXWQSk/JDCzrWyPsZ73fITEVj/hIHbiLu6shSB1owYPa1suq4eF5XD7B459s
xQpSq5tYLrNrJj93RjHUmQwSdyfATjk3cHDbPntTwYNYzU/xDTCCKZ/fECcdJY5f
BdEosvuA33eS7fUGl/X41J90xfE1YX1voaSuXcqvml8OYLLHkfARcCgQcnXhddLu
kv7hxzFaH92lBJCSw+kxQ2Y8/ckZweMQae9Iri5zO/PQADSlXZ4q1ZPYi3P3W9Mu
xpZ5SngftunG2ow3hy+cXsZbip8LSX/WUhaqLRXFtDYHYEAo2adm++fwakL3nwe4
Hi6KRStfgEolmIXOqx8v8k02XtPF8lRGVOt5fY5TfQhto76hBlpjwKc8f+erPQmY
LR3+uZ3/mZOplTvXM5gHeyj3WYUHIG8kbXF/DQR9vywjtGhvs52scKjNxWi913G+
uetZYdLknn5sZJ6vFuoS0HXI5mbRIe/pYJiyYY5QFf4PqPEuCCXEU97LbK/DiKLS
UQHy6Ql+XMh7N5vGIuGfO3UUViUxHVI9YPUWPnYcg+r9lsqlVQK+ONQ7UvPpv5K0
ihl7wn2WLDVU8vGKdJoEpVguzTGDRYjexARXujma0m3ZWg==
=qFim
-----END PGP MESSAGE-----
fp: 88823A75ECAA786B0FF38B148E401478A3FBEF72
- created_at: "2023-05-17T02:31:40Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0/D4ws+/KPtAQ//SZnnBl2yscyGe/91Askyrj911GXu3OLIt7FRbkxzrPm0
301N6KuwAWn5iMG51Phh1OD7Xiv9z16R5FjD2J9NQOdSXZ03u2QKY0Pp4Pq+3bVQ
bm2B5HGDFlf2mjAPzsXrBCK0YmP6vOm5ehZX10p5j8RcvgkzZMELdiPtMa6Gw1lB
KpQSCw52E4yyqmHoe9bu9tCaNd0L3lcEnbwDz9iRc+vCmdnJvzIQZeSQqv4iU9qZ
fhwDvNd63ntBjdtV9EtvP662Y1IsQkL9fdSHBQYxOEmov859i1LkVxZI5EkB1ebI
H3BmK4EO1oJEE8LDoZkcue4RXAJbwfOy6ReN6Ds4Q+tgAdJdKL+sq48UrA/AHp+d
dxxsoZzKUc3GXq24lpjVr6uvdBBl037GRtyVvCisQRjp/Vh7IKFtWvkv70Vh7/1U
8k3vi7r6EZbpw1dBwFpRX54xVkXXbYR9NQJLep6E13Nbx9M3GVT4C9ylRV5T/fNQ
0sKEhLT5kS6hiS6iTDyWVuvH68YnBGiQRTDYBBpuy6pEqbVY7kOoQutwzRCEyzlP
eXccctyrS8EzcJVv+WVI4nxC5ufkDnDSGxQwNrkpJa0n16RZSJKuLpnytLlAYjRB
6Qw0fzjkNMM0y0mpoae9hbfou5m2d2+kX3ZJzObBvaZSpmXQFKwVZFwMFxl+bWLS
UQFiF9SZqHa1xPE99LIumWOZKY9G4EgUekcPfXXtGhJVo36a7kTa2gJpEFNl15EY
V/BoOL83x1WB1TEOH9kAEj7tBcOHb36vRy5SQuDr0O4fPw==
=Ybcm
-----END PGP MESSAGE-----
fp: 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -0,0 +1,33 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kube-system
resources:
- cloud-controller-manager
- csi-driver
- csi-driver/webhook
generators:
- secret-generator.yaml
replacements:
- source:
kind: Certificate
fieldPath: metadata.namespace
targets:
- select:
kind: ValidatingWebhookConfiguration
fieldPaths:
- metadata.annotations.[cert-manager.io/inject-ca-from]
options:
delimiter: /
- source:
kind: Service
fieldPath: metadata.namespace
name: snapshot-validation-service
targets:
- select:
kind: Certificate
name: snapshot-validation
fieldPaths:
- spec.dnsNames.1
options:
delimiter: .
index: 1

View File

@ -0,0 +1,31 @@
#!/bin/sh
if test -t 1; then
# This is not foolproof. Can easily be beat by doing |cat. This is just to
# make it less likely that secrets are output to terminal.
echo "Error: Not outputting secret to stdout; redirect output to a file or" \
"pipe output to \`sops\`." >/dev/stderr
exit 1
fi
printf_stderr() {
printf "$@" > /dev/stderr
}
printf_stderr "DigitalOcean VPC ID: "
read DO_VPC_ID
printf_stderr "DigitalOcean Token: "
stty -echo
read DO_TOKEN
stty echo
echo > /dev/stderr
cat <<EOF
apiVersion: v1
kind: Secret
metadata:
name: digitalocean
stringData:
vpc-id: ${DO_VPC_ID}
access-token: ${DO_TOKEN}
EOF

View File

@ -0,0 +1,6 @@
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
name: ksops
files:
- ./digitalocean-config.enc.yaml

View File

@ -0,0 +1,23 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
spec:
template:
spec:
containers:
- name: external-dns
args:
- --source=service
- --source=ingress
- --provider=digitalocean
- --registry=txt
- --txt-owner-id=external-dns
- --txt-prefix=_owner.
- --log-level=debug
env:
- name: DO_TOKEN
valueFrom:
secretKeyRef:
name: digitalocean
key: access-token

View File

@ -0,0 +1,18 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: external-dns
resources:
- https://github.com/kubernetes-sigs/external-dns/kustomize?ref=d00387c92999e0c1530b144713a318bd1a5b6a17
- namespace.yaml
generators:
- secret-generator.yaml
patches:
- path: digitalocean-provider.yaml
target:
group: apps
version: v1
kind: Deployment
name: external-dns
images:
- name: registry.k8s.io/external-dns/external-dns
newTag: v0.13.4@sha256:b1ee7b829bd4c8bc5fbae0e4671cc423304a5a4c8228dc13e2c961c1e5eb90e4

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: external-dns

View File

@ -0,0 +1,6 @@
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
name: ksops
files:
- ../digitalocean/digitalocean-config.enc.yaml

View File

@ -0,0 +1,89 @@
RUN_MODE = prod
RUN_USER = git
[repository]
ROOT = /data/git/repositories
[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
[repository.upload]
TEMP_PATH = /data/gitea/uploads
[server]
APP_DATA_PATH = /data/gitea
HTTP_PORT = 8080
DISABLE_SSH = false
SSH_PORT = 22
SSH_LISTEN_PORT = 22
LFS_START_SERVER = true
OFFLINE_MODE = false
[database]
DB_TYPE = postgres
LOG_SQL = false
SCHEMA =
SSL_MODE = require
CHARSET = utf8
[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
[session]
PROVIDER_CONFIG = /data/gitea/sessions
PROVIDER = file
[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
[attachment]
PATH = /data/gitea/attachments
[log]
MODE = console
LEVEL = info
ROUTER = console
ROOT_PATH = /data/gitea/log
[security]
INSTALL_LOCK = true
REVERSE_PROXY_LIMIT = 1
REVERSE_PROXY_TRUSTED_PROXIES = *
PASSWORD_HASH_ALGO = pbkdf2_hi
[service]
DISABLE_REGISTRATION = true
REQUIRE_SIGNIN_VIEW = false
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
[lfs]
PATH = /data/git/lfs
[mailer]
ENABLED = false
[openid]
ENABLE_OPENID_SIGNIN = false
ENABLE_OPENID_SIGNUP = false
[oauth2]
ENABLE = false
[oauth2_client]
ENABLE_AUTO_REGISTRATION = true
[cron.update_checker]
ENABLED = false
[repository.pull-request]
DEFAULT_MERGE_STYLE = merge
[repository.signing]
DEFAULT_TRUST_MODEL = committer

View File

@ -0,0 +1,24 @@
# Secrets
Forgejo requires three secret keys, each protecting a specific component. They
are generated using the Forgejo container, to ensure they are in the correct
format. These keys can be generated by running:
```sh
sh kustomizations/forgejo/scripts/generate-forgejo-secret.sh | sops --encrypt --encrypted-regex='^(data|stringData)$' --input-type=yaml --output-type=yaml /dev/stdin > kustomizations/forgejo/forgejo-config.enc.yaml
```
Forgejo supports SSH but requires host keys to be pregenerated:
```sh
sh kustomizations/forgejo/scripts/generate-forgejo-ssh-secret.sh | sops --encrypt --encrypted-regex='^(data|stringData)$' --input-type=yaml --output-type=yaml /dev/stdin > kustomizations/forgejo/forgejo-ssh-keys.enc.yaml
```
To get the database credentials, run:
```sh
sops exec-env secrets/production.enc.env 'terraform -chdir=infra/main output -json' | jq '.database_users.value.forgejo' | sops --encrypt --encrypted-regex '^(data|stringData)$' --input-type=json --output-type=yaml /dev/stdin > kustomizations/forgejo/postgres-auth.enc.yaml
```
Check the Keycloak Kustomization documentation for information on generating
a Client ID and Secret.

View File

@ -0,0 +1,79 @@
apiVersion: v1
kind: Secret
metadata:
name: forgejo-config
stringData:
GITEA__SERVER__LFS_JWT_SECRET: ENC[AES256_GCM,data:v6EWWeq0MDTcxesXXdZ9s5YMAiLNhy5f3mdGZKDOl4j25DX9T9Y5hzhdZA==,iv:PDjtO0bKbpHJVMCsQ+DNwmLwqp4hn+mMpIK1j72JUkg=,tag:N2s9jjz3Hal1FcU0dcOveg==,type:str]
GITEA__SECURITY__SECRET_KEY: ENC[AES256_GCM,data:Ny0s7FUbcSJC7EjInhCgcRUACwIU2jz8qo9QhEzSVckvG1d8uwSfJ3sa45tE/hITP0T5m94ofrAEHwaTmQ0mow==,iv:iZrJPznGkkD++wS+EF564/QilKT53yZaS2h9SBQdJhI=,tag:kh/jySPF9qZ9BZ3JkP9zpQ==,type:str]
GITEA__SECURITY__INTERNAL_TOKEN: ENC[AES256_GCM,data:tZtCtZ4vMd1M4M6b4f9qCp9jjLgRyo1Xo//63qXxZkRdgvvGg0NkS4bRS16Y4ZjR7uofAk18ZgXLseRN6uiJujAwif+82Hilc9FWOOXYU4ni9sJX2YyJg0oTICjxlinB43mFuBzmMuW5,iv:WkanY0QfLKRjc5D1fJzSgUojxf47pla0BfecomNqISM=,tag:i4DQS6pwCruRPS7c7d/+Tw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-05-17T04:43:13Z"
mac: ENC[AES256_GCM,data:iVoGf44NRRbZJJ7zZFxKeqt9ab81+XrWJXzKkfGHxh5CNPtY6Ruq7v9W3KZkoHUhci3xWdm+0WbJVioNLb4zxbg1cdqxcQ+4HDPnCWR6pfE4lsvjfPCDJ/hraphewWisKpjbIV39o6LyfmaRh2gAkirFiCWI8DZRJ7RF9HRI25Y=,iv:z0gPB+pAHC/sBU+hjMw66wK5NpIvpx/XMvj0XHjbn/4=,tag:eG/iF4oq/s4jX9aBqXgsMg==,type:str]
pgp:
- created_at: "2023-05-17T04:43:10Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA82rPM2mSf/aAQ//d8WAKvmjk8Y3z9AdY2d1mAvwupoiJsJbrRkbmiXigBsm
FYcwTHFF6ML96ml6/g5P3C8m+S73FcnzLBZzaL2IIih2B3e59J+7Ol3xi3shcSek
e4o5GuSITH1QdsXU+JzgdNrVFRXrEUTmaf60aKK6ejBW+ki+Q6xxPrGt92M4XN6E
qyTS2G6wTJoGfgG0NUTrBUPBmhHND2D8TK0ijvf8VkEX/YXYp7N5E0b2jkU3Qn6x
6UQ1Xv4jOoB8+8pZaPZp+9W0EmJ+V6K2yEEpqGzNed898caCT8XLLfgjTbe4sYZk
h5iC3ORitKR1OgNthRXhojbkBtgVxqYN6q7gl+jstKF7AhLBDx8uSC+bAI/YTHRi
zjBJK6aI40cyJDTsEHGnTGRn5Egdl0zjyiDdwFGZ+n67ynw9ge/fNZvMlnYpkVcq
SD6hP9HL0Nl+LSH2HJ7E0ANKKKfuOTwJdFicafMXbafgy9vLM+SC+riGSoC732V9
AU6Hi/rEV9uaHFah67RSf2Y/KHZCIU3pGSkZ5vrEHrPAb8rdvVXOndBGfrbNg1++
dOOrwMbdeS9qusivhBN6CLJcTu7OB/XU1IBaF4lG91ZUoGkirIPv3lhbcL7MWPLS
CSr9ptCSWqtutXe8/I9VIkWzuICKOKBgDiZwRRVtlHSHo4BqF0Wav/IN2hSYg8rS
UQFvCdj0zyjJLwdUkPYQnx7jUI1AwZ2d/GdFKsXf1zy/Lx5EO2Dniyns/7cEtc47
sCvlv15vb+WNAPBJ6/8EohALQefbzusWIzdBkZZtV9pVhg==
=IA+Z
-----END PGP MESSAGE-----
fp: 6B61ECD76088748C70590D55E90A401336C8AAA9
- created_at: "2023-05-17T04:43:10Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMAw95Vf08z8oUARAAwkO6Di1YjlZoYFq9XHqVm/Njd+p8PpfE2q1Ay5WCM8gc
FGUoeZ/zcS/dPRVwI6m04SjCi2Vld2Z8usZ3l2vpVgNEiZe+a3nzPkRbJno7J6xE
6kQggHFcvAira++lLvQ6T0xN0SXzOmGhBIcAz9OqbAR2dPY/9eFj+LDUJmBNlMo6
A4ZaKVjCy3VzwFluLkCkztcdVAKwQ3bK0ZVi0L73IHxYI57W+Jv8h9n6Dvh5wbDP
aDwv8K/f8m9QRXUkb2DXtQzs/LFY6mCxO3ZKrkbujZX1wIJR79a3FVJnGKFeqhAU
3EdxempGP1nipEy52zVjaKKccI4qVN3N4LwZDoyGnVBHgiVLTBMjNPyYKyveZ0r4
YHoB4brHX4Az7MiDZpOoxoFvRNrtk+I8GRJrlNNeMcFny5d2oZm/ANYO77AnLw83
SYWs7ACYeahKadWQ5qfeGTdgNFGxZtZIPzkaTVlGXOcLdKCnbiW2kpPhmNna4OT+
kac3aICyyntVNrRY05CVB28UPWhJBer8zVhGaIhzeoJ3YJjbMqNJKffl9yWVtN+j
NamZRl1TTwBPo/S+7Nq/r+h6nUQzLiaWz0SxvDab2he4qTG4T9RxOycohUwoeFnF
tXGgQMwfxRoURbjmYpLdxWi6LTt/xWzPl0ld1UgcBcPOwMUQAzXvQ4NoKQ5pmtvS
UQGYOcN9JicX594J7QU54T2OHwMvj6NZyVaLGu/t58tXE81qT6hzP5/cQQ7dhIBo
HZ/IJ8EdgCebogdsVxQHyiq3kuPIoO7dlkQFwvH9Z9H8Xg==
=Q/2s
-----END PGP MESSAGE-----
fp: 88823A75ECAA786B0FF38B148E401478A3FBEF72
- created_at: "2023-05-17T04:43:10Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0/D4ws+/KPtAQ//SPnqWp8yvDWogXPa/SLAnRKRiCHrMGZrrYMGL5I8neBC
AvYeOSLu5KB8QZpffUP3Mz/SLVJ8MJ1aBiqwxBDQZ3dPrJJt59Bg3CHD5hbtE278
6rAup7KG3AqdXlPrMg0J8cZo+278/SJqb6sxtc7BbVG2fWK/e2Ps0bcVZb9HFKWP
eHHdJs+9A89oWieYfoLPAB9MZpiW0SgPQ6+TxQ5AAxTw+5Nc97bRwpgoKyM8k0nE
PYWLz9jFrvEb3TxLinrDi4ir4bK3pDYjP4/Q4IAjPhXs6ECCiOcCb39vBKnVctf4
2QBQDmDuiINKShYAk8EcmhAfnNS/213LH/hkVXndRhDrUGYb0CdxFS1xfbtaf51c
xlnmXOH9+2TqAqP61VOF3i4qMx2EMNMAjP6GpaWFyIIB0x+j7mMhBykq7EfMpALa
QFqc/E223fdTXGse/VYkHCw0JkEI7XHf8/OnqHjnUTdIpgMMv6NTH9NNeftIhFeF
GqDElRtvC3H/COvU0bUluq4Xrjqo666kbmcwPD1I3pY7R/4IgoOGK5y/sxXlGcLe
UjzIClxvqmVdGTwzDRELR1+p5ld67ZUJcufXzGrDTqP46bjUOI/Pz3K3NXLaVLzV
j5Stl/4apoGCfTphINZhZrqsA3RwtX6Fc8gEH75ZBh200ZP94vNcJFVN2Tlo6wPS
UQG+fz96l/oxi+EZfaQMqpHALsfDDyYecXm0gm1ZlugHx+bXE51MkpskIiKIHJwz
UZiLgKV3Sd9EQ7vTf4uuOp6LIsv+/iWdVCj3Qe1JQ2vHzA==
=MzCR
-----END PGP MESSAGE-----
fp: 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -0,0 +1,39 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: forgejo
spec:
template:
spec:
initContainers:
- name: config-templater
envFrom:
- configMapRef:
name: forgejo-config
- secretRef:
name: forgejo-config
env:
- name: GITEA__DATABASE__HOST
valueFrom:
secretKeyRef:
name: database-configuration
key: address
- name: GITEA__DATABASE__NAME
valueFrom:
secretKeyRef:
name: database-configuration
key: dbname
- name: GITEA__DATABASE__USER
valueFrom:
secretKeyRef:
name: database-configuration
key: name
- name: GITEA__DATABASE__PASSWD
valueFrom:
secretKeyRef:
name: database-configuration
key: password
- name: forgejo-oidc
envFrom:
- secretRef:
name: keycloak-client-config

View File

@ -0,0 +1,84 @@
apiVersion: v1
kind: Secret
metadata:
name: forgejo-ssh-keys
data:
ssh_host_ecdsa_key.pub: ENC[AES256_GCM,data:VOuGvQnelnYCk4s/yR74K2IOowM5184AZhW0YuJ0S49bSD7YU9zratOYRwHLdNBRha7fJMLPg+eLCNgB1qMTQ8PyYbZHFvqazXP9jJ/E2MM/1MBK1XlcHEajg3Of3FqQRmIVHjhOc1e8tNUsmV9GAXZJD64v74hQ5XmWaNE3f3y5C6MKDwZV2pWpHMt+vaMgl0Jz6WhXjgXKYXJzoKb96vXrbRKMhFRNEMYuxjolvqXUNCtfT70uRuzycUrEPG6ULizamhl942zClMv0h35947oDslYCpiGvZCtOqEpfkzGqyfSwMd4iERJC3bM=,iv:oszLiZd2oUUdr4mWaNOktcR0HSkc2UYpJDl6s3plRII=,tag:VluUpN9DD6dRXJR6L87sVA==,type:str]
ssh_host_dsa_key.pub: ENC[AES256_GCM,data:y2/S8DPOdIZstIjuCWYcYYXF2vzjCBDrhuNgp8E0Ir34THUO3gLBy5ZILp7YlRFzUihNrn7OyxxUMOaIo0ruKRK7ST844+cJCS76b0fDFNHTnApOWJHmoghITrax32JEfymZcaFQG4Sp1qDYNHasquOxSlVRNBxJuW8w2+l1DsNKJczTVYOhQbRoVXdjXWPS1tELO6sKkyAnxDblAyUKiPByhwl559rFUApZeep5hLI2O2+x6uNh55IHrFkUUu9i0sDuIArS0RuQTtXkdceJm/A2JIBec2htgg9S7gq5Tppr9PDIPgTBXtOeiwOT2Po12EW3rSzazFGrg3NXiHExnXdiIlRM/dTYXQc1L3k1U9iqk7tUwYh1jBNqdM36htBtUD7+ttxF4Bc2lqyaS9Ct0YGr0cxlhQw6qYTGmtaPyndRsN9ryt8n7Di3KySvWrBPoPb3x6+WwMMqTerTSAJbCdscz3+ahGAiAX4RA7iobzbKdsP4H/8UmNax/BK9E6qDzc8EAsTzCKIsISeapCY71Vw2K8y/kR60tIxaHQBx5Fp7MAj5HJENN/he49RGp3qIwK4W+IOBBIlAxUM9WxTw7lw+NKMSWQMzSuAtf3uVIHcJ1WmooBxV1pF2NvxmX81iVFZWfN0+XAq7l53a7mFoPH6ah1r6RUmRZZwHJDOiXRu4jQDrN4Spi2abpVa4wdnoa4Hjph4c1Lx42OPPLq4O0TMCeGNoK3glMyndHh9wYOR3yJ9qglUvvZs9HemxgvaWlKu4bb1jw5Wh8Hnfv0XpXllJOb2zKOU7HPRSk6Rdqz6pG1a0aUEW7nk/17HVHQXZ6fnfMZqQ3PyNPbZ+FSkJ4enaLkexNmci5zOAEu9ExQPoJANxsNTahn1XrIs/OrkScKhAbaGoDGtTQSWB9hg78qpeUhy688OOz6a7wevOpA3N+hJFxqTErTvFqCqK63Lgyksb/tneihpKgkwWGhJ1WIDMzuoC8H3lYnEvqRvS/nvDM8Kh0mo5u0gUmPvfX9bMfY4elrXROn8rVHai8fVaOx7HurAQth6xWy2qhvLBoKugjxBI,iv:55i0lL5O2DLsoOobvqKB7syMRsgoN8Jj2YnDxYnYL2U=,tag:7H5gGB8IMbw5kPEVyOSZOw==,type:str]
ssh_host_rsa_key: ENC[AES256_GCM,data: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,iv:DfGvCUw0zPaJtB6uehT9djO1a9+n/vL6SVumOmCnHDw=,tag:aw7E2tKk+o919VpqXUYs2A==,type:str]
ssh_host_ed25519_key: ENC[AES256_GCM,data:eVTvUJntXwzjVaxabrDKmYHykDhauzgRCr3eB1FH7ou08Ezc9j6jLvzKIss5dAFjQzF8nR7U+KvNMH/trpbpoH31qL8xZMXNY9Qra41Js1DZh2PMUdwscHKu6iJOPOPX2DnONicmC6KZaP8aBL8si/jrCJ8C4AUC8VsyyAWwcuDr0+ADn0vkghiPCUtw0kIoVs+d2ToGMQwsi+5hGF8ku/9SFBdui6SnHv7XWpFC/DfxnznEigJr8v4USHiB3uK4258Kj8BgaSagI7cdqP8taYsvZelH3m2WbptQ0dn8mZRQyca45nGs/xyRjYpDtTSwPVlQyXdU0k62rvbKK65iDLoQF2TMajP14laKQFYG7bd2Y9/4MfzPct9hMWvbuUPhCh5Bo38e08ZYv1asCDr8l0x1zubUg4LXDMy/aiF/lOIkvoOSKPw40uhMn24vp1y4GeKHoyR0x2d8UgUhN2QinRr3EWVJzndAVs6NHDWZbZLbWS+nXOZVOw6/Bq9GoJLMupoHcz9pjs6HiROdD4gRRPfB/RBzYdAUpuXsjpQVPx7qdrwuClYwy44Ex/lwQiQPW28ieSK+BlwaQRxGZp5xoH6JeVai/C3nmrKRYneOOmLyAmhdY0D32lGFoGqlPZ+iLLOYELaEIW1dVbUV7p05Nwe/Mzssg/nrfqif/OiRfzVYCd1vMoMmaZugNYSFz7WcfkgzDw==,iv:HfJ0YQc9rgtETGWM/dDtVW1J3NUOHwerk1kA7nBaYxw=,tag:+LULyDdw97kFFXJspTmsag==,type:str]
ssh_host_ecdsa_key: ENC[AES256_GCM,data:8MtNsOG9GhNjV9R9naHEWboUTGDpmxerBkWRbAsqoMkuG7cgbEHqsNPEm2EiFj53Oxjv9cxn/Y1eGPpRZBFJwcuxbz/9X67e0PvQT4HLaGUCYARMB14Dbuj2OvyLrR4WzO1jEgcPYcRr5T+ah/qDGDZIH/pr8solkxpHlzfeHA5yVT1u0TQh+Per5EMW/z5/dyhTEcyEQSTnB5N73rG+P6lkD4mFOWIgMFXkiz0eeKf6QGY+wgsxkHEsJp5dH0r0B66u+7/0+HnhCfVqFuSCQBpwATW4+u01KnBDBc0otRE0DY94jB9g1LSFQ213sVFrvlVv5ElBLhGbJwg1vF16vv+frUnYlr3kV/71/2t4LGdWme1hMoZJdNZtrC9rrjODKpMBNP3AjijQ0Uf+epak02oodF/RImQi6fa+CksrUMNtLlaahVmugAlrHQHJg/qdZwfZbKPtXbspmVV9zW7n3yuW7DHHb0+Ofnkvuncvo6kO5WITxqLT/9y3lPa83tC1D9Jz861UMR6v7qVULwRr/gD/49VQU35hdL/YYa0vwHgUb55mo75zEJW2RhT011IkbgLOqPVDRlWF8jJvMvthfdxejxrldYFFJlShKfvNtBpA1NFpfU+QKJ/6na5DPmpNmVMZx/CwW/oKxgy/2Di0rBPcfl5F7skX+coHFr6sSlmKBYHQ9ZpKP0i0l5C/CYXnfmHcTjdeQ5C3DAMv+wW49j9HXfcVf7QVQctNd9rbS4ykZCiiz8kus6jC0JNCL8B+lolm1YC8PSYpeLdQ3jqtshtW+GSTeJ0Yl3b6fvGR0TjUTUEKHKTC7j2Rw17okLNJ1dP1UFKR1z+LVqXLPIz3wSLhR7fZYTjyo69emCTk2YLDmCGeX6hPxtfnaTB5wmk3rAX+Kg==,iv:7OXES/JmVsTgbxAyYPhMKUyV1hdCAR/Z9H/Li3H/0jA=,tag:ZvRegm/H0QayQkR5LRuHaw==,type:str]
ssh_host_ed25519_key.pub: ENC[AES256_GCM,data:EZWxrJsDmWoSyj65UYvDWv9cLNDGf6NATsE05e4LmOdfDQdeeHH100Erl0fgGqFB+6JW4U2wx9/C0sQFcvK8jPQDyMkW4jfEeqkNJgVhIYi8EccAEbEKQudlAn+DeOZYnjy5NTjgUnaeqvJWl/O0hj/T4pAr1O7Og1+qE3M3MoE=,iv:oq/xU27MRVMl/4qbVlWJ4Sg6xgDjSmRzoI+xMGcgdCw=,tag:x9+EHPXgCt7SeDNsXgeZ1w==,type:str]
ssh_host_dsa_key: ENC[AES256_GCM,data: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,iv:BBmbPDgCFJKWnAD2pGnZPvm+xFr+ZKUrp1cGp+IP23A=,tag:p/zYGDrfhpWppTUxR7k3GQ==,type:str]
ssh_host_rsa_key.pub: ENC[AES256_GCM,data:PpkYt+LpDvSWVqdtcXKLB3FF6izqfDhDGWQGrPADjOE1dukUW910Np1cM4R7JOKmio5yTE5lwXrk+t6/egc19Hu81oyPToZjpgsAhsOoQ7k/zbbf9/NqigVTku7zqyehO30E4508U0Pg/Ih6KM4xE6kqWOPEJcpCzIdKo/xVaJskM06XgbRUcPpPUKaZd9o313jwDXYnduoi5vo7/KdX3t5g2wBNbMcURXgVYdny6k1HsDNE7ouT6r8gKzLbAdA0qgmFkToQv8a/IBrIKtKvcGbsiyH4DRChZP0k7wqvxptBkq7dxPvp3xbQuBO0cKNWA859ICMt97OC/hYq0tYvc1n8X7IW8rfVHMu6/OHdHCMhxwAcTwUkGvRW9P0grLtjlHgkxlnOB75r/qfBNHoN0UV/nfrto3H5jWD5Dc1PDU6CqugVVxePLs8uJ660Mm8+2if75N20GBXyJkEXj2ZAQmVYhQbD2GGuvXQCyKt5jytSqwW/VQ3xWBvbKRVH58Y7qfRwC8d9/g6u5kjdqeTkNKGLRy0L33KhI7HAlmjE5nD7B97g5tjnTEFyfVFZI1B+nBIF1CbmKFkkbYkQCrdFedqoLiSSdzduvnjBgc6S5gLRkNnuEaO7DMvBjviCD/9h4LtvGuXtvPCtABZcTnV5vnDEOylhCXK5qh+xWHEfxqB3c1iqC/dMSAv0LuUiwvvL5Ao+gZdCuOILz/eV3KUwXEQHEyQu8scq0H+kPKFg8x8GGldyxgbz6Jr83PZxXRGSF/rOGU9bvwuv1I4a6nIe9B6W9HEgWit+uGPJ+pETARJIrbGRtbwelaWg7UTjJFsu/JumvhT5o+DO+TVhvOGofHxKuYtQKf2smsst80nDFqsa6T5II6X7mge536XbILynnuGkDJ7UkTkA6FGTJ43m3vE5hI4wj8Lu2xq4nEplxL6V/2WmmQWK13kzP7Qk3BzeS1i6IliS92Z1tvuUAk+yH+ojzJ7I3CRTF4SG49ri2uo2Nait,iv:MzcAxHb7Vy1eFRhVzrb7kV+Ut39DEpIV1taGvHqIB28=,tag:Ttui1RIhjtpuKlZ2X2ckIg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-05-17T04:43:20Z"
mac: ENC[AES256_GCM,data:ckF80Njd6BQXJpQ4X2z0Os5wvfZ2zjXVyTqtGQ5fFIBDoGa3tWgzIel98xIRgx4f71kKisBsWg3ofxn/3gG1DR5vx8EJwpekpcsTq1e8z4ZKFeGTIMwPb9GdWKUJBvuMxv7dQxmM6HgpwkUsEFUaxmNnOmetK3o1g9LMN0VSpuU=,iv:VTLGM8ZAFsFDNcUop6sqfw5QBRFtmzDdZHWxHMHmzow=,tag:e/KQ0ytN6HfSJohGAtGcNg==,type:str]
pgp:
- created_at: "2023-05-17T04:43:19Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA82rPM2mSf/aAQ/8DF+bts51IM4cxJqEvN2hM5e4bkI24dE8/eNfMtzL2+WA
sF9LSXsKOf5SQgjLq2wHFRdXw0Oh8KouaeL8FgE57lcFNWnIenKoQH0QbxfeKXL3
UGiDK4tD3hdoFEkUIS0fFHnv+gwnRIcYXe3VXfUR1v6Zu/TCZkuw6NSSILLW+9ta
1pIccfmiAuhDtLcE99E6/XPfMXDmrnNZISA5eYTP3ln/+dPPMZvsm7EXFu90Sjd3
qyjLffoMFz978XuBxzTfBkSLynMDyb6uMFIQ/bLb3qGOBXV8f8hr4F4iH5K0E+eA
/NOSih9JO1R9EmCwl2s9peu/bjmuLMkCr0tRmS9qIrZP4TEgFLRtm30ZCBgeO86c
PYlmvo4u8SF34X7HOjB0NfJJr7xZbVHV1pUoHEsLUrHHKbKzZZso+azH3CBqVDjw
szeZDl7zRLVnIOhFQiEa6kX1pONFMBma8zktGTK6uIAP81G/tIVXIW71P++v8udn
pfvxeaC+lNZ+HmoHF8KiDbuL+tOPbTfrCCTmPMhWUtyYL0H4Zbh5am91WLCwl3Z9
dOfYa6gEdN4Ci4M2X+NoaHaQmO76ED2aXXa9tbmxosXZha4m7FqbDQwLGpeskC7t
Q7QTzuPSpdkMcBclz4WmCRWgsF8lhc8z5n7VrpHKQmJssk0Veac7ZijOZWf4v/TS
UQFyrke/EqP4r1WotIyLosgAii6k5Iystwx1N25w9ta8VXfL9GY6Abj3/yOA7p2a
valV9RGUSLWHf3MilQtToL1RSTYC20By7ojhPMFsw6i8SQ==
=eLtw
-----END PGP MESSAGE-----
fp: 6B61ECD76088748C70590D55E90A401336C8AAA9
- created_at: "2023-05-17T04:43:19Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMAw95Vf08z8oUARAAmkFuy2s31HF8E3rwLKrJEkYMLMslUARI5hhk9RShydwt
ZeY/pshfGxd3H1z+gLmRa/iqiD4Iyhvtj51vOnnpWgetfnLfrd9BN5fP86kiNJqY
LS0uLlNnlA3Wl5Q3qMXBRb2FqLQZKsoryGbwigmyFoDSmt50Cib7j4EABKUmA8Az
ZZMN+65v6a0t9owyTFOTV/rJLwgo9TcXZJuoo/RoynBzKxpxEVMhN0eTn0B9qX6Y
ttO2eLWB5vUWtU/FbXRtleROwns6K8vueQ9EKFxYs2CAK8rwii44Gb3VhIMyPHqA
UrMaCXPJUOKYPlFribGSnjFfc2cRhaeJIb/AxCUtEerRBPqhO+PGNPMX6fTSpwl8
xz4gno0DmDKGAv4a9onPEbCCMko57kcZT3s3maTE0Pm3PqeVXh5CZYtFxZx12Ngs
GsYYadOdTBPw9mfTdPuWx3DBrdSVEIT94DQfKoPJLMLAJm3B18wGhGeYZXj883Gn
R9eHA7w55BI6e8cxbMKBceXi+JVRr0QZxQe7YwgpjW8utjRQy7Cc98wnw4+6TE0e
WkqeisiunxCpVLaNgAeJdzjtfawjiu+/AOMGjj06cJMv6zIUVOXKNrP8rv5AVumF
uNw1C/QFhEPbDIOt4yfD8hBtKYckY9iRv1/mTav5eGQVeX+vsnXDStlEOkhdx+LS
UQFi2I88txzZK503LB5fPW/asHVDay8ZItA1fZZFCzew0kqIzEIdsdiDMf/qa2I0
dBKvq0s4fDjkropJWsR9c5/rG1LDU20/UZ78CTfdpKx89Q==
=ALmU
-----END PGP MESSAGE-----
fp: 88823A75ECAA786B0FF38B148E401478A3FBEF72
- created_at: "2023-05-17T04:43:19Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0/D4ws+/KPtAQ/+JH3bDOtFbLGQs6oYu0eyNTNwME4bzbyh1AUPPZeCx/2+
vfRpHX/3C1jg9NPAg95yC+xJwMVxjGthAUE5jGznMr8tpv6dMCp9PINrYm1X7OU4
C4lrlDRJ1Nyi+eWrDzN933kq997kMHAVC6LdErTOFKRfZ3PrG+MBZcJJM/6pCa+8
iLDOTsbq4bXzctRZxVRmuwZfPfWHn4zZNpqo7IMRfYknfIoVUKRkHZBz8vXxPjFy
Llhr2bC30ZrTBwSuIApxIv0r6dwReuW4eIHXSVlNDPB9NjmbT20bh3oshhRHanCK
sIlc5YxS8zbycnpF4CRM25wXeBSSxbtBUeh65ciVuHWQyuGseybjzo2wPKe9KiDr
fMG5Sq/NhS+LkMcGDzs5rk7yf1HCmTBdotHhmf6VzHXxfctvJ6Q68Sv/kjJeyPmP
8/flvcf12CeeR11Au05W2ZmhbftwqwIaxHYif3kCwMf3jf79ZghvCORhAuEOELV3
am86dAFAu6aSrQI9V4tqFK3sbHOCY+gtzRLhD/E11+h5o+fyApz/5ZBuyv1QJ89C
Lf8NQMQdm5FJgeI9kIOFGtkDtrHFtI1Fewcf4A50ieQ6jA0aIfms5LLo/eqjeONY
iKFUS0wg/Le6wCm+2z+dfYp96e7FEglFBacKB+WSqRdbyFiDthPPh/0nZYOAEObS
UQGdn9EdcRnpSaEkOMACNmHYMfn/WIFC+wlwZTFhn+QXS2XyXxPqxR1XR5SDazCU
e4iBPpnfiklTSRHKg99a/AeV0pMdfjlVBd1PTS9CX6OScA==
=/Opr
-----END PGP MESSAGE-----
fp: 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -0,0 +1,54 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: forgejo
spec:
template:
spec:
initContainers:
- name: forgejo-ssh-key-prep
image: codeberg.org/forgejo/forgejo:1.19.3-0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["sh"]
args:
- -c
- |-
cd /in
for file in *; do
cp $file /out
echo >> "/out/$file"
chmod go-rw "/out/$file"
done
volumeMounts:
- name: forgejo-ssh-keys-secret
mountPath: /in
- name: forgejo-ssh-keys
mountPath: /out
containers:
- name: forgejo-ssh
args:
- -D
- -e
- -p
- "2222"
- -o
- PidFile=/tmp/sshd.pid
- -h
- /etc/ssh/keys/ssh_host_ecdsa_key
- -h
- /etc/ssh/keys/ssh_host_ed25519_key
- -h
- /etc/ssh/keys/ssh_host_rsa_key
volumeMounts:
- name: forgejo-ssh-keys
mountPath: /etc/ssh/keys
volumes:
- name: forgejo-ssh-keys-secret
secret:
secretName: forgejo-ssh-keys
- name: forgejo-ssh-keys
emptyDir: {}

View File

@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: forgejo
annotations:
cert-manager.io/cluster-issuer: letsencrypt
external-dns.alpha.kubernetes.io/hostname: git.distrust.co
spec:
ingressClassName: nginx
rules:
- host: git.distrust.co
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: forgejo
port:
number: 80
tls:
- hosts:
- git.distrust.co
secretName: website-tls

View File

@ -0,0 +1,80 @@
apiVersion: v1
kind: Secret
metadata:
name: keycloak-client-config
stringData:
AUTH_PROVIDER_NAME: ENC[AES256_GCM,data:x56JkJ9hJ8w=,iv:dSi/y/gO7G6fyEV01NwwQYiNFCFmbdJ6Nx7WF3tT0B8=,tag:/UZXBBTmzJ+UCKxBukqE/g==,type:str]
AUTH_PROVIDER_KEY: ENC[AES256_GCM,data:aUXX3mqFuA==,iv:u1O9OgTk95ASgSbpNchlFs8UMPuqpPubbbx+oD9DPlo=,tag:FZ4W0dsBx+1bGI5oqeT+UA==,type:str]
AUTH_PROVIDER_SECRET: ENC[AES256_GCM,data:YlLZnS6d3pDvVLmB8UH4b97cC4OX2r5YZlvhygI4ZO0=,iv:/QET+u0xwYBH0hMI91ApcgTMhDoNJn2HUbhiIdukH5E=,tag:FhR6ER/rto18QaPG0XmBwg==,type:str]
AUTH_PROVIDER_URL: ENC[AES256_GCM,data:ObcwDFglRD7QcbbSo9HbvDoScOCEuIuGMakuh7IgDofbrgvI1wfizrHPx2ERqn39hvzMeAnm33PAOmHq1sJGAmjFNOYOFPd0PZtxmW0=,iv:LcDQUz8gO32iukWwzhJSLShtATPKbXB+BHE5FNe8WoM=,tag:9SPGXZO9MTa2CACuYQ/LBw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-05-17T04:42:46Z"
mac: ENC[AES256_GCM,data:yEhIqMzYb1AJIcKkU/8lizXMrhQf8Sm+WvTUp0O0OcBn8eP2RRyTpX5CCk0///Dv/FonfheKTz77Hfs6L+8OY3GU+WxBmo+5F9ACZ4aGLHldvw60gLH5J7PmR7TD2L7D0EE9OMD2EeTKV4NJA0AV63W7PT/Vr7rO0EITGz1RgCE=,iv:OwfyaH1V9KwkEBrrclSMqT5uDjM6s27MkJuQTGoWei4=,tag:65kiPK6WSIAReLJudDkM5A==,type:str]
pgp:
- created_at: "2023-05-17T04:42:30Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA82rPM2mSf/aAQ//QbHBxGnGu3SQZ9hQBeKirQ4BuoBTntPQpW+696a0Fb2y
5qvkdTHwJ95HEhTDhXtvppSUlqxvjfmSp+Ps/h9gHIEkH9C8W6Cl3EvRmIwv6wVc
ur9KSuSOJydTDKwnXlGyYaQy5o+JATENAwNRd3F8ttP2KhphroDidfAdArr6EGcV
rTAvNIAWSkDxffPrA+3o5iNd92LGQH52CDzOcad4TipK1eMnMC8sEAza39pm5DIe
FfOv8tnpI5Tz2wX8HiayCHXIzYNKPMHMp6SQKfxOZ4jjeisajOwvhNvesK1K3ozy
JStxI1qREZauI9j6HOPDgNvFe+qe1y8c/Ua+gMaK3pGkGAIOa90EfR6ANO2Dr91i
5F15eog4ONzeQ8mP6bEk0Ehcvn4kolMpgk3tAVJDHS3TMuVWUyyjA4CrKbfgAqQp
7sh9qGG9lgD/uAtm/cja+VsOPisr7e4Mejbv3yWFvCmx6d78U3To4luLd4TxfB7d
TIx9FP32rRxzOiMAOQ/s8vDor1PfoCQEAxSrX3f1QjoR8bHWshcb5v9XhwkpDpeE
UlkLLoqnkPcerXlwUX3kCgO8gW4yx/IwsfxwiZUirG51+m3+P1Cm3grrBqX2+v1U
u8jtlDjFhTBO4NUKniPrfDz7okuBMlrYM8zMWKnERBO7zbVjNZMgtAIkihV04szS
UQH9gVSicEixmM2Cms0RqQiGRzSU8gqzXfrVu6sDxSTcVUByANzC7qqnEjowCWKX
TJ6jJrR7MtSJ2JUHjOLM2vD+FdEbEjN8InMmA5nbFpsGiA==
=vrRi
-----END PGP MESSAGE-----
fp: 6B61ECD76088748C70590D55E90A401336C8AAA9
- created_at: "2023-05-17T04:42:30Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMAw95Vf08z8oUAQ/+LTd9cwkweVOtvlNxBLlwoxA9sYRXkzXXUGMefpf4C+WG
RtWxwsH3FDjaE5FhT05knXDfNZ9R5Q7JHCCYXx2rGDVOuA0Xw/CAVBg4sRXI/97A
H9STSgGyPR3wnltiZTEMHRjVN/ka0oK54/1Is8TBCU+1iB0VGEHemij5mEwe+uZ3
rX9WhsdMokMyfLdM2bTCstTXZxlhJog/VL+JnGJqSlZIUFoLt9koo33yfKzAEs6h
dFLODFtRqdxkEEdOdQ3Ph8UesS7Q5FV/nnrz8QVQUIySL2Ac8GWSpQn3UDh7CrNi
r9eVbijlPkWQk9XbOVn/XN5bssZhhzqgkgPROleInaoUe4lvwa5dxEJm5VAaYkE5
MgTtTDCahF3p9kvALMYTeAfZGytdPR2T7emi9uoBwkEDX0C7c/SMjiXnvzlq3nm4
zjoO+dYxfnTcX+kguyvg006517viUuDT6muXdUD82XAEEMjuoIlgqpwNabkjk10c
T2uKWKgCpaDTPplowup6TC1YtYvhfaAAY+lGpM4iNBEhwvgeh/L27cr7+SnFSH25
7ekNUtGR2WapP2ptQ5wvKE71u2HrhxnjYRMnG+7PjeXeumBsljeS9hX6ubSLulkl
vEPKaL904ab447rmU2OxuDGUmdBsVGRVpeDUTF147kTE0+1rGYcPTloLHEyT3pnS
UQE0dY3HJwY/mg0nFJk6ZF2az9igIsKwzqAkUXg9uhELZlNG8LSQzlOQ1z2NPa+f
6wqqQXawx9YeKSZg4+Ew++JX0Dma+t/NWZSgSlWJAm2HaA==
=W0PJ
-----END PGP MESSAGE-----
fp: 88823A75ECAA786B0FF38B148E401478A3FBEF72
- created_at: "2023-05-17T04:42:30Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0/D4ws+/KPtAQ//Yv+SwxWvr1vkaCIW3l3RCE0Uq0T2cxxfoaqYJvvaKfIq
YkF2TZWAa8JLicQss56K0Gvk8nvltjwX5j0AZ90PdIS4+ju+OjeGnFso86xSb3hv
xE6fItMXRW/DUqF515waU628W8J4UhiiZjTX3BtvVP4cXmh/Cj3yXY58eblLqn2V
DGS/YNG7UeHlZm6myUJ9jfaqer98rYGcLZubQQZOi8iQLgau4uj04/sp5QGwLkZZ
wQ1Thlwss9Fx2FZgCibtk6Wo69peb33NsJC/muTP1mk9lfEZolMhPaGHE4ESb0dd
MloJyJALQZT9jwvkTk3Wi6tT86LUYTo97AjykNN5WdcRHL3K2HTHWSIGQBIm9xW6
L1HWcLUGuPaXeMN1PHRZyFoqnT0wxvYOxW3BHUz+50+3fq1OKF5Tq7nxPUOU1OP1
5JerRvtQHZYpiStfwZb3vObLHAW33wY5+e/IRtbO+i8TPG4fHd+wfK2KwdQyNYoj
JBrddff11tu4YQmvPzI2HouavtHNK+YuaOGHHuI6o31NvnJTPcB+R0nkDPrpHOXA
UXahuEJjWLjSRwBZiUjDuDtYmVzkN/0Pb3IUZP13zNQOffbl6p9X57jHkryF7qUv
rRKZBhSAyPrwjvpr2EnAdEThl4gu91tIWh3lNKJRz30w9rtcn6Erqa84bTcPaI/S
UQGyFGUWQ/fZ4STq43owUuOKgvk/p6PLDBqAiMpO73eXzqr7tUP/ZQhESAno6BB7
OqdEI8SS2FXS7YYdox/DdnUZC2AB39/W3mwSUKCAs3XTQg==
=XdhT
-----END PGP MESSAGE-----
fp: 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -0,0 +1,37 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: forgejo
resources:
- namespace.yaml
- resources.yaml
- ingress.yaml
- snapshots
patches:
- path: forgejo-env-vars.patch.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: forgejo
- path: forgejo-ssh-keys.patch.yaml
target:
group: apps
version: v1
kind: StatefulSet
name: forgejo
generators:
- secret-generator.yaml
configMapGenerator:
- name: forgejo-config
literals:
- GITEA__DEFAULT__APP_NAME=Forgejo
- GITEA__SERVER__DOMAIN=git.distrust.co
- GITEA__SERVER__SSH_DOMAIN=git.distrust.co
- GITEA__SERVER__ROOT_URL=https://git.distrust.co
- GITEA__SERVICE__NO_REPLY_ADDRESS=noreply.distrust.co
- name: forgejo-config-template
files:
- app_template.ini
images:
- name: codeberg.org/forgejo/forgejo:1.19.3-0
newTag: 1.19.3-0@sha256:e1e2a9930afe7e4e6c53b7d250072e5f890894da71df681510b6b513f38d0c36

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: forgejo

View File

@ -0,0 +1,83 @@
apiVersion: v1
kind: Secret
metadata:
name: database-configuration
stringData:
address: ENC[AES256_GCM,data:63ZDrBbSqC3AA1ih+Y5voTw65P9TMfjJkkOdvyAN06dNHahzGtANQk1QOF4hf7aY07XHJ/BCYB6pr1IzzqKbKnE=,iv:8vkk8TlbsZ8zCHw5bm4b3e5rbxNuAMLn9cfBs+eUMKo=,tag:9AxSNd5AoHLes9GLVtL+AQ==,type:str]
dbname: ENC[AES256_GCM,data:0y+eZJ4qzQ==,iv:mCSRJKjQIeobFKlsIAwCi2fn/g4JmweQYs2w/7g8ah0=,tag:t8afmjnuTu/RIkv3TPr9wA==,type:str]
host: ENC[AES256_GCM,data:24ZodubPg2+uKRc9cXMY7l7hkzb4D9xVQB5n3hKwcEZk2z6pQB9H2zZGix/TmpOofvuF9v02kz/6Ro4=,iv:RkxOm/VzGFmuwfdBgmqIsMdfU2sDIgN5MzrkCcWdDSQ=,tag:/bIx1wpTjPNbNrdV7fqvBA==,type:str]
jdbc_url: ENC[AES256_GCM,data:od/PVm0tWTJLKQpYDOPDNTa2GOeQu9yk9XpvDPdJLwwmpaoXmw2KwdXBsdlCeb2PS6oc7g1K9b4bgUgQsbJ9M1lS74VnXPSZP/lcvmimhCfkdAtll4HxfQpSe32KiAAeWqS2lVejMt6VDIg=,iv:9+y0N4VR3O/3ROMSfklCp9WlNjpOJp2/2DwO3h0/Gfc=,tag:2ImzBaEqV4oVIDsZYS6prg==,type:str]
name: ENC[AES256_GCM,data:mapnSTvdaw==,iv:i8aIKJAMmwh2dLZn3tOXPa/VWF90CSb9V0NEuPMWjIc=,tag:JmsbcOm+zMgSnke8MpZ9PQ==,type:str]
password: ENC[AES256_GCM,data:Kz23HQT5u+qArZ8XzcUYq86ACimqRpib,iv:2oOpxRqqz1r7gTVmVkeTN64iJAJ31WtwSg6oSneP7Nk=,tag:ugDCQk4SROxu/38tnyBy0A==,type:str]
port: ENC[AES256_GCM,data:THs19H0=,iv:ClV3x4MqLoKtJpeBbiDUYPgaSu0s/0app82jfE/J8jE=,tag:iSM57k3nE5LQ3UBJq3oCIQ==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-05-17T04:51:07Z"
mac: ENC[AES256_GCM,data:VkAYUP6gCIxXq282+aeqeBj9kYNemw3C3k5+twxv58nhz8rFlzXKwEpRmi38WH1mM13bcp5usVz98pIKGZ00kh1BOE8LtvFbyUUBH/WqRBAZBFcuBC94Z9llVMDlZMaUTmSI6bPOF5ZMtB7YieSU8fgfWYm2+jaSLNPc3BiE3k4=,iv:ypClxnTavYFW3PJ9non3YKAUcLHjXN1YpaMIcVRw2DU=,tag:q07HOHb+Njn3xyZ/RgFJEQ==,type:str]
pgp:
- created_at: "2023-05-17T04:51:03Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA82rPM2mSf/aAQ/9Fxsu+M3vAwsBt81ttsgqmbuNT9GJs/kaq8wCEn8bXb6b
Z6xMZjkPpBrpLw9kTm7xNfWEAtSZlEaOZk2JdnzX3pkoavbU39U0rPasOtBeQCPJ
Uh183yK6AfLz9T/y9Gtd1ucSKQc06GcjgefOJcPvkQSytLHK1LYkEb8P49f9rvHQ
dzh0SJ/+UT2m8J6U4tf6v4fzKfV1QQP1J+02EBxqgQEMWf5VpGQMUyUaWF9tqnrY
mTIrwWrBLII/cZhmeTAmW6xcGJhcqV56Wp43CClKlWkQWW5VsxYOI4jYSzpp5h3Q
cIVqJa7wPc1queZ7QT++hoyKm1rgRkUbJUWldVDdsbRpaNYvLbeNbNP/5hymnTSA
TC6GLOCXaE8oD05Ej9c6B2Dudo4bL0gzncgy5d8/EHyVGwaidjfvUTbIbEnXPLHN
k5UuLyPWxbGmmJgBmPFBoKmyNb1z88PCfoSe8//aC1BHzpHUU4ttAC2/WJ0VQXn4
jvK1t8OD3NjjLUivwgVY47eOsoM58lMeSwhY1cqXgA+Lg5QwLvmNZ56ZjzHAHcU/
MHX/fIe90UQsyyhnsdC//6e8g5Md+Ogn4R0sck8b1OLXw0xyssFmnq00HLYWF/k+
zLWt0AQVjsBYbvPMar5qEXo37Dv5ysxDVMG/DiRc9tpTxEtThITHTbiG6H2CLiLS
UQFewalfgutwUre8yghgrwJPJFcwo0biG+sE3Fy1p8DbUJdvsbcQcgGQ9Xbo/H0X
ER9tesFK5lV23nYsKwIRFBk1sZhkHFw0hF3hgZGhNwU6NA==
=3cqS
-----END PGP MESSAGE-----
fp: 6B61ECD76088748C70590D55E90A401336C8AAA9
- created_at: "2023-05-17T04:51:03Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMAw95Vf08z8oUAQ//e8sNyX/ceOkWiYJGzRC7/zN0Wwc8tj6bz/4iIkKBI3cX
mSjr045rVerNvlKQEZhFmJ6Prde75nTeY+JQtn9NF/EpqJq7WLpP/K7W71zXiSLA
1KKLDGqgSK29+OuVoqPpdA47yo9GJ6BEZAaUvglI7pKzcC3IdQ3qasqeGippVLRG
KU7hANcLQ5n6Z5gRzOfXsVkn4PA3Oc+vlNu5mPjISEx/o9oRHM9oPRxa4icQ+RgD
L+8CxXNfkHdgUg/epJj4XAa8wBKkuQwZRorXeeD3Dc7EVGo8j0sWmwf7jQrYewWq
Mw4VRnCtrYMvh+3edNWM1OzOwEC3qFbdu1rUj49REQzThtjLgTCi8Or6hmOe95Pn
o1yZMMqb4WMr9gm6rioc2AJSUfqXa8dZY2/HzxGXXn78PXb/9jnbDqlxBquQsx9S
SUiZHEhYXeT0H8xjJYTSen47H3QlTzJwNaDjFvkeTbXuk//l7Qh8bP1ZliloFrCM
OPKgFiaB3gaNoCVr+QIwC4ya12mp1A4IsqEujNePbTF9QyT1Y6D2vIAsWKRpaSgH
9yr/KR5afNpJmadS0njCWuYGE0CPrpEaN9TVn+uBph9MGJhgxun69eeNOtLgvUg2
d9WYHbsEyA+AdLISZ5z1MNJodQ42SZEkWepqFvcmqcW2lCEJAocGLVyMhcXZvarS
UQHVNU1yswZrkL5T4BApriFU1MnS5u+w+nwrnIOha/a0wcFf7YAuLuXKoD64jgmd
HnpzkynR0ncvUma3DLd9PuZvVmfbdaDk3gyRj9qWhwij/g==
=U4Oi
-----END PGP MESSAGE-----
fp: 88823A75ECAA786B0FF38B148E401478A3FBEF72
- created_at: "2023-05-17T04:51:03Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0/D4ws+/KPtAQ/9GEZwphMFiR9xUS089WmTbX9SDrKicEFbAgtVxWlf7R+m
1WxYsWvGxPJE270Ts8ATjESmByM0u/CuQiH9g3j4gYfSAUc/+N6oXugMsFT5nuNO
mZoAow11aaI3SIqmMaGJw8lvPtYhjEk3yCSF6iRN/7evzT8XtrEZa7eAkqyrNJpP
wv6ISYeP8TPxj5PredQC+vqhr2CnfsR1yEwtZU3NYetKpFpo+esV1Nb3Yw4nA0ET
r9pSSCPVTIu80nMwVLxn4pLK7BujlloqkAl9ohpa+VtBLI5Tt2/qVqpRjvvy7KiJ
sYgO26nZC2zVp9DORlCprjnMR5IjQUMq/YZK7pOhTbG/XeLauxSiA7teQJmkPvWT
mvM8++s4frf6P8qDHdZykkx90sINxX4o8HhNDTsV+w9VIjEBNVITjVddIXkwwR9H
VZYdUosGwoUpRKmy0U1BIkfhoRQYZIBpGskkZ8NXK6D6qFjtKYxGv+87Ubb8C+n6
vbLuJcpFYTgQrY5VMkXv0zeJHCxCtrPCNQsXVrfekvgG+MvaCeXQKYWVLwdoAZqO
M4yscPtIbeFMneaGYgJN8S2JoSnmQr0ECo+mVyK1R2gCk6814AAjtlmX/VhGnBrt
AZ790+9MfvyxYbpp0t+hwHYd8CaDJsaoU32xmQ9v1+RVCQTJVDjJNZONZPiFRifS
UQEnAC6OyQbE4BpJLWCfDi9bQEfUXRsc/YoP9/H5/0CsdqitAKJDUWZ2bQyo7K00
zZjB5LBAbBv+mljI6/CDBNJ9EEJ9gkFv4+cn85CfmcacVg==
=oFfs
-----END PGP MESSAGE-----
fp: 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -0,0 +1,178 @@
apiVersion: v1
kind: Service
metadata:
name: forgejo
labels:
app: forgejo
spec:
ports:
- name: http
port: 80
targetPort: http
- name: ssh
port: 22
targetPort: ssh
selector:
app: forgejo
type: ClusterIP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: forgejo
labels:
app: forgejo
spec:
replicas: 1
selector:
matchLabels:
app: forgejo
serviceName: forgejo
template:
metadata:
labels:
app: forgejo
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
seccompProfile:
type: RuntimeDefault
initContainers:
- name: forgejo-ensure-directories
image: codeberg.org/forgejo/forgejo:1.19.3-0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["sh"]
args:
- -c
- |-
mkdir -p /data/git/.ssh
mkdir -p /data/gitea
chmod go-rwx /data/git/.ssh
chmod go-rwx /data/gitea
volumeMounts:
- name: forgejo-data
mountPath: /data
- name: config-templater
image: codeberg.org/forgejo/forgejo:1.19.3-0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["environment-to-ini"]
args:
- --config
- /input/app_template.ini
- --out
- /output/app.ini
volumeMounts:
- name: forgejo-config-template
mountPath: /input
- name: forgejo-config
mountPath: /output
- name: forgejo-migrate
image: codeberg.org/forgejo/forgejo:1.19.3-0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["forgejo"]
args:
- -c
- /etc/forgejo/app.ini
- migrate
volumeMounts:
- name: forgejo-data
mountPath: /data
- name: forgejo-config
mountPath: /etc/forgejo
- name: forgejo-oidc
image: codeberg.org/forgejo/forgejo:1.19.3-0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["sh"]
args:
- -c
- >-
forgejo -c /etc/forgejo/app.ini admin auth add-oauth
--name $(AUTH_PROVIDER_NAME)
--provider openidConnect
--key $(AUTH_PROVIDER_KEY)
--secret $(AUTH_PROVIDER_SECRET)
--auto-discover-url $(AUTH_PROVIDER_URL)
|| true
volumeMounts:
- name: forgejo-data
mountPath: /data
- name: forgejo-config
mountPath: /etc/forgejo
containers:
- name: forgejo-web
image: codeberg.org/forgejo/forgejo:1.19.3-0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["forgejo"]
args:
- -c
- /etc/forgejo/app.ini
- web
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: forgejo-data
mountPath: /data
- name: forgejo-config
mountPath: /etc/forgejo
- name: forgejo-ssh
image: codeberg.org/forgejo/forgejo:1.19.3-0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["/usr/sbin/sshd"]
args:
- -D
- -e
- -p
- "2222"
- -o
- PidFile=/tmp/sshd.pid
ports:
- containerPort: 2222
name: ssh
volumeMounts:
- name: forgejo-data
mountPath: /data
- name: forgejo-config
mountPath: /etc/forgejo
volumes:
- name: forgejo-config
emptyDir: {}
- name: forgejo-config-template
configMap:
name: forgejo-config-template
volumeClaimTemplates:
- metadata:
name: forgejo-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi

View File

@ -0,0 +1,33 @@
#!/bin/sh
if test -t 1; then
# This is not foolproof. Can easily be beat by doing |cat. This is just to
# make it less likely that secrets are output to terminal.
echo "Error: Not outputting secret to stdout; redirect output to a file or" \
"pipe output to \`sops\`." >/dev/stderr
exit 1
fi
FORGEJO_VERSION="1.19.3"
FORGEJO_TAG="sha256:e1e2a9930afe7e4e6c53b7d250072e5f890894da71df681510b6b513f38d0c36"
FORGEJO_SLUG="${FORGEJO_VERSION}@${FORGEJO_TAG}"
forgejo() {
# TODO: make this extract image tag from kustomization?
docker run "codeberg.org/forgejo/forgejo:$FORGEJO_SLUG" forgejo "$@"
}
GITEA__SERVER__LFS_JWT_SECRET="$(forgejo generate secret LFS_JWT_SECRET)"
GITEA__SECURITY__SECRET_KEY="$(forgejo generate secret SECRET_KEY)"
GITEA__SECURITY__INTERNAL_TOKEN="$(forgejo generate secret INTERNAL_TOKEN)"
cat <<EOF
apiVersion: v1
kind: Secret
metadata:
name: forgejo-config
stringData:
GITEA__SERVER__LFS_JWT_SECRET: ${GITEA__SERVER__LFS_JWT_SECRET}
GITEA__SECURITY__SECRET_KEY: ${GITEA__SECURITY__SECRET_KEY}
GITEA__SECURITY__INTERNAL_TOKEN: ${GITEA__SECURITY__INTERNAL_TOKEN}
EOF

View File

@ -0,0 +1,27 @@
#!/bin/sh
if test -t 1; then
# This is not foolproof. Can easily be beat by doing |cat. This is just to
# make it less likely that secrets are output to terminal.
echo "Error: Not outputting secret to stdout; redirect output to a file or" \
"pipe output to \`sops\`." >/dev/stderr
exit 1
fi
tmpdir="$(mktemp -d)"
mkdir -p "$tmpdir/etc/ssh"
ssh-keygen -Af "$tmpdir" 1>&2
cat <<EOF
apiVersion: v1
kind: Secret
metadata:
name: forgejo-ssh-keys
data:
EOF
for file in $(find "$tmpdir"); do
if test -f "$file"; then
echo " $(basename $file): $(base64 -w 0 $file)"
fi
done

View File

@ -0,0 +1,9 @@
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
name: forgejo
files:
- ./forgejo-config.enc.yaml
- ./forgejo-ssh-keys.enc.yaml
- ./keycloak-client-config.enc.yaml
- ./postgres-auth.enc.yaml

View File

@ -0,0 +1,7 @@
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: TEMPLATE_NAME
spec:
source:
persistentVolumeClaimName: TEMPLATE_PVC_NAME

View File

@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- resources.yaml
- rbac.yaml
configMapGenerator:
- name: forgejo-volume-snapshot-template
files:
- forgejo-volume-snapshot-template.yaml
images:
- name: bitnami/kubectl
newTag: 1.27.1@sha256:5e9d4cf927e21f51f99f9ec64eda94b3a7cebb66d4da9676081817f8f480fd2b

View File

@ -0,0 +1,42 @@
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
name: forgejo-snapshot
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: forgejo-snapshot
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- snapshot.storage.k8s.io
resources:
- volumesnapshots
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: forgejo-snapshot
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: forgejo-snapshot
subjects:
- kind: ServiceAccount
name: forgejo-snapshot
namespace: default

View File

@ -0,0 +1,89 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: snapshot-creator
spec:
schedule: "@daily"
jobTemplate:
spec:
template:
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
restartPolicy: OnFailure
serviceAccountName: forgejo-snapshot
initContainers:
- name: template-snapshot-name
image: bitnami/kubectl:1.27.1
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["/bin/sh"]
args:
- -c
- |-
sed \
-e "s/TEMPLATE_NAME/forgejo-snapshot-$(date -u --rfc-3339=date)/" \
-e "s/TEMPLATE_PVC_NAME/forgejo-data-forgejo-0/" \
< /in/forgejo-volume-snapshot-template.yaml \
> /out/forgejo-volume-snapshot.yaml
volumeMounts:
- name: snapshot-template
mountPath: /in
- name: snapshot-yaml
mountPath: /out
containers:
- name: create-volume-snapshot
image: bitnami/kubectl:1.27.1
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
args:
- -n
- $(POD_NAMESPACE)
- apply
- -f
- /in/forgejo-volume-snapshot.yaml
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: snapshot-yaml
mountPath: /in
- name: cleanup-volume-snapshot
image: bitnami/kubectl:1.27.1
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
command: ["sh"]
args:
- -c
- |-
datestr="$(date -d '2 weeks ago' -Ins --utc | sed 's/+0000/Z/')"
kubectl -n forgejo get volumesnapshots \
--template '{{range .items}}{{.metadata.name}} {{.metadata.creationTimestamp}}{{"\n"}}{{end}}' \
| while read snapshot_name snapshot_date; do
echo "$snapshot_name" "$snapshot_date" "$datestr" | awk '$2 <= $3 { print $1 }'
done \
| xargs -n 1 kubectl -n $(POD_NAMESPACE) delete volumesnapshot "$snapshot_name"
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumes:
- name: snapshot-template
configMap:
name: forgejo-volume-snapshot-template
- name: snapshot-yaml
emptyDir: {}

View File

@ -0,0 +1,6 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx

View File

@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonLabels:
app.kubernetes.io/component: controller
resources:
- ingressclass.yaml
- rbac.yaml
- resources.yaml
- webhook.yaml
images:
- name: registry.k8s.io/ingress-nginx/controller
newTag: v1.7.1@sha256:7244b95ea47bddcb8267c1e625fb163fc183ef55448855e3ac52a7b260a60407

View File

@ -0,0 +1,177 @@
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
name: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resourceNames:
- ingress-controller-leader
resources:
- leases
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
# NOTE: Can be overwritten by Kustomization
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
# NOTE: Can be overwritten by Kustomization
namespace: default

View File

@ -0,0 +1,121 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingress-nginx-controller
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
template:
spec:
containers:
- args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/tls.crt
- --validating-webhook-key=/usr/local/certificates/tls.key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 22
name: ssh
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
spec:
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
- appProtocol: ssh
name: ssh
port: 22
protocol: TCP
targetPort: ssh
type: LoadBalancer

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller-admission
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
type: ClusterIP

View File

@ -0,0 +1,38 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ingress-nginx
commonLabels:
app.kubernetes.io/name: ingress-nginx
resources:
- controller/
- webhook/
- namespace.yaml
- tcp-services-cm.yaml
configMapGenerator:
- name: ingress-nginx-controller
options:
disableNameSuffixHash: true
replacements:
- source:
kind: Certificate
fieldPath: metadata.namespace
targets:
- select:
kind: ValidatingWebhookConfiguration
fieldPaths:
- metadata.annotations.[cert-manager.io/inject-ca-from]
options:
delimiter: /
- source:
kind: Service
fieldPath: metadata.namespace
name: ingress-nginx-controller-admission
targets:
- select:
kind: Certificate
name: ingress-nginx-admission
fieldPaths:
- spec.dnsNames.1
options:
delimiter: .
index: 1

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: tcp-services
data:
"22": "forgejo/forgejo:22"

View File

@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configurations:
- kustomizeconfig.yaml
commonLabels:
app.kubernetes.io/component: admission-webhook
resources:
- resources.yaml

View File

@ -0,0 +1,7 @@
nameReference:
- kind: Issuer
group: cert-manager.io
fieldSpecs:
- kind: Certificate
group: cert-manager.io
path: spec/issuerRef/name

View File

@ -0,0 +1,49 @@
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ingress-nginx-admission
spec:
dnsNames:
- ingress-nginx-controller-admission
- ingress-nginx-controller-admission.default.svc
issuerRef:
kind: Issuer
name: selfsigned-issuer
secretName: ingress-nginx-admission
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: ingress-nginx-admission
annotations:
cert-manager.io/inject-ca-from: default/ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: default
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
timeoutSeconds: 29

View File

@ -0,0 +1,39 @@
# Initial Setup
To generate the admin password for Keycloak, run:
```sh
sh kustomizations/keycloak/scripts/generate-keycloak-secret.sh \
| sops --encrypt --encrypted-regex '^(data|stringData)$' \
--input-type=yaml --output-type=yaml /dev/stdin \
> kustomizations/keycloak/keycloak-config.enc.yaml
```
To get the database credentials, run:
```sh
sops exec-env secrets/production.enc.env 'terraform -chdir=infra/main output -json' | jq '.database_users.value.keycloak' | sops --encrypt --encrypted-regex '^(data|stringData)$' --input-type=json --output-type=yaml /dev/stdin > kustomizations/keycloak/postgres-auth.enc.yaml
```
# Adding Clients
Clients are how Keycloak authenticates a user with a third party service. This
happens by enabling a "Flow" when adding a client. The "Standard" flow has the
user's browser get a short-lived authorization token from Keycloak, send the
authorization token to the client, then the client request a long-lived access
token from Keycloak. This way, the access token is never given to the client.
"Direct Access Grants" means that a user may pass their Keycloak credentials to
the client, then the client may use those credentials to authenticate with
Keycloak and get an access token. In this manner, the client still does not
expose the access token to the user, but the user exposes their Keycloak
credentials to the client.
When a Client is created, the Client Secret can be encrypted to a ksops Secret
using the following script (Forgejo used as an example):
```sh
sh kustomizations/keycloak/scripts/generate-keycloak-client-secret.sh \
| sops --encrypt --encrypted-regex '^(data|stringData)$' \
--input-type=yaml --output-type=yaml /dev/stdin \
> kustomizations/forgejo/keycloak-client-config.enc.yaml
```

View File

@ -0,0 +1,17 @@
By default, Keycloak configures a "master" realm. This realm is used for
administrative purposes, configuring data in Keycloak. In order for Keycloak to
be useful, realms, clients, and users need to be created. Realms are a
collection of clients and users. Clients are third party services that can use
OAuth2 and OpenID Connect to authenticate users.
# Distrust (distrust)
This realm is for members of Distrust, enabling them to log into Distrust
hosted services.
**Clients:**
```
- name: forgejo
credential_type: client_id_and_secret
```

View File

@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: keycloak
annotations:
cert-manager.io/cluster-issuer: letsencrypt
external-dns.alpha.kubernetes.io/hostname: keycloak.distrust.co
spec:
ingressClassName: nginx
rules:
- host: keycloak.distrust.co
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: keycloak
port:
number: 80
tls:
- hosts:
- keycloak.distrust.co
secretName: website-tls

View File

@ -0,0 +1,78 @@
apiVersion: v1
kind: Secret
metadata:
name: keycloak-config
stringData:
admin: ENC[AES256_GCM,data:OpUQVXI=,iv:itDUevA4gnLKfES92DtN6SY3vtu5fu88eVCUQ9KzWrE=,tag:4/8hmDdIS7ADSLcBN+Welg==,type:str]
admin_password: ENC[AES256_GCM,data:H+RUQnraa7mK7v1wxNC/AVo/bcoxyd16yQXKUjQtP5U=,iv:B4ZaALHHfYo0U93ZVupHdQmnHz/ctwbe+/pxoMivaTM=,tag:FsGmdez+eEhpi9XZs6ayow==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-05-17T02:36:37Z"
mac: ENC[AES256_GCM,data:Q88SLpF5oLkWM/nCsrmjjnaqwvjZSkbpiuUzTHOPNO1YcPYupuUfiMm5vmwfAl2Z7KXJWDaQgwmRAwb8XId4XOS/5jF8B5wddyusiXqt/Lw5f73XN2BO4KNwJnj4Xz90je1eeC7yRpIIOcMvNL0OQT2JxxYG6HGg3YnXpVVXT0w=,iv:ZwCgmGiOaRWCnxMUZdnII5trS7mh3r9AOubV911wjN0=,tag:6ta5SGvbDtQgZ+omxCU39A==,type:str]
pgp:
- created_at: "2023-05-17T02:36:36Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA82rPM2mSf/aAQ/8DTrA2HnRfcn/VY9betvfUJIK3aCKUfFIVTfKm2PoMXBp
vV2rTiR2iZa8+6YPPJWVR+S7s5MQBBkcUshd9KGUoRj55Oq/imZqoS210vofAa4E
/gvhBgamVDHthqNBX7GLDKVS2P383B/X4u7k0cB+CPKTM8j9gytWQbXwQwCwSWoQ
8ihfqsjCVpSvJ+WH3rVoz+EfjB72R1NJZHZ5/nU1OlaY6XFe8oh4vup7w1LGOSvi
cJBr8i3ylN0zT9MKORmksut25zMlWkKxm+qfsCBg1yZbNdDMWQLGvAxg+VuQUZEA
nIvIerPgXH5scKUSqN7koSMpxjzFv89NpAWGOt9/9prl1gHmXEzG2TNAyoYbDY3y
lPXldbQBVYwFLMNg/HIGxVzwpge2YXMCVZVQgvRLsIhRVCCMnZhFYhkctrnnaBQy
WkCBHFHqHhu+kVHr9pPDD4j3KOPMMJwCVJVUHNhPNjWBI2OKR4cmf69go6j6VrKv
AuMFkEQvfwMz4Trj2dWpNC1ZY9mHyR0oSzXCDu/FQuxuR6LXtGozbWF0wtt1qUpg
niik9rNWNgL87L6qXzRGOl1SawpxreOXrc/dnqt9aflO991FKm+2XrNgDOAYXjpM
i8ug3Rrk8W9u2GatXaSQNTOADfUVxhhjA7dV17NNTyOKV2rRZkho3NfMxha62QPS
UQGMpAYBmLwgorNfpN7AhTJs7gDZFXHOytH+Kb+4blxg+XkAsnMUEGacp5t95mBr
Q50a5nc8M8g6r6N4QGcVAOPpaWAPEnU+8hzv4Pdb8xyCxQ==
=AmmI
-----END PGP MESSAGE-----
fp: 6B61ECD76088748C70590D55E90A401336C8AAA9
- created_at: "2023-05-17T02:36:36Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMAw95Vf08z8oUARAAjbyM0k0I2kxY2e6ZULFXNjdYTkmtij/dJK/Y5TkvphzI
JUL+sgXaf9GH4xOreRYbLkg31JGh/XF3ONqRBKxmShkbY14igDp+TBKLAx5jQChD
OxZPLGWjum2n3UrfBq0tV6SQMBt3HNHRboq4ao0Epd7XrErx4banJkxujUaE+Dqv
wh/FfQvNRGXC/L3v9BUs4lJfZcL0ICx1fuIxh/TvnA0WFkpz2KwCsQFspb7WhTkr
QMbrztB1QK575Kp/iex/3oejxs7QxGIM8n03Wcla1NzE4fLLToYa0lhW/vkS9n5f
daTm0ctbZdIlWyMLl5hJ4pm7y0Gj5Q/5QDxpyPY2TK6LF53hzVnmy6fWhn1QPtwQ
+mwm5d/e9I15SyjvvYvQW3DWRl+HTPdzUaw8vL5gmOMpkZEbGYRJ7SyKKKM6xiHr
rCd4mDw+Hls8A0j9okmz8biErGEn07tW3t9ToaBL+wj7ukb2S+6HbAgOm+SRkG9L
Fb9eQEcb3yDOs1HOMFexWMHIlYYV+Y1LBQEytcY6aVrXbCmJH6xOpimHP9yrKO/s
kvMW/sEqHFT+5ZNcg7ygtnsXcPP+0NNzxbia4KLwezGlsQr8631hqItllHVW/OB+
Pfaij6/txbFJeD2x6kyKjo93vBMWz3R5DocMZoNRlS8yAfF0XbJDAlX//opnKVbS
UQHgTgpE74vpL09C6ZnbSkM6fwUUiyFjHXH3W189w5QWcwOZNBCutMxtzJiLD4Pz
iFR2IYU470OZHGw3nMpJwmg1WXcInwyIlKPBhf7ugqSazw==
=qUVy
-----END PGP MESSAGE-----
fp: 88823A75ECAA786B0FF38B148E401478A3FBEF72
- created_at: "2023-05-17T02:36:36Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0/D4ws+/KPtARAAjHUXCr+VjVF9mqQzipmFsyl8qmAUB/IoV3REoWkUAOJQ
xI7OWq+Pt1Kp0Wz57uvw2L2foyCApvSI59yhs0mmO4RHkUGOJ/Ni1BvTCqeHXF2y
2Q8OSG721Kj63XB1H0tfxNnWMdaHkVbyVbzsBcKXJCddOcrLTR8i70ewzL5eX++M
5EEyrtSgc75DcPdR0g4wYK9nlAAiArK2F318bdMNqi3njzRvtGA+G+SBazt+yeE0
9kH7o7EZ28mroew4SHc0t2S17UoiRgCO4KE2UbjdETB2zEZ+Cii5UT5fFjanPG0d
/boVpNcSwqz08LlZqAHUt5Rf8V5oGca5a08dgcX71AJgH+sZW5AkBb9uKlVUU7k3
xQUMwKBhNPTwjCGkSoKAvGD9E6PwBQbR2jTm1VFjhXKklz3t4xl8e4HwrULhCiNG
Cjw/t0BsL88HVBS30Je4wKbgAgkhEkPfpR0dJuwugLNJoVbnUViuQnOjnPIM9d2y
f4DttIOtlqReID8FA8yb47gFyn6NFUD5uVJshyxeGN0RLgOhMcQyC1DJp+V+SQt0
essZvLGbadnbsaJx62CvzyOpDCrb8S2gC4s0XGT/d/6cSj9l+cCV0jybpe2V6z2R
wyuPeiC3Nqr2qtTZSev7Z7qslcQLZuBBJbu1AzPx+IuUtsp/F3ypAsTb/I8UCbrS
UQHNNGhyoMZfeVduEy1jf1PvXeVM6dJNY/D02H6E/tJUnqhp/e05SZ0IZeS+K9dJ
Deq5BhkkwpjjSYhNenmTWSP7K+yJ9WJQ+a1RuWFVQfWynA==
=xngZ
-----END PGP MESSAGE-----
fp: 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -0,0 +1,21 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: keycloak
resources:
- namespace.yaml
- resources.yaml
- ingress.yaml
generators:
- secret-generator.yaml
configMapGenerator:
- name: keycloak-config
literals:
- KC_HOSTNAME_URL=https://keycloak.distrust.co
patches:
- path: postgres-auth.patch.yaml
target:
kind: Deployment
name: keycloak
images:
- name: quay.io/keycloak/keycloak:21.1.1
newTag: 21.1.1@sha256:8ebb3930c41e8a066c4246eaf351ac09cdc984e11b1f607d6ff4ce10d69dc808

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: Keycloak

View File

@ -0,0 +1,83 @@
apiVersion: v1
kind: Secret
metadata:
name: database-configuration
stringData:
address: ENC[AES256_GCM,data:nTcQhHWOxhcL6sDsDxA5c0qxlXZ4tg6GZvEPuEOLDppFoRpOvk7nPojG2zqaZQRO1hHzaf2UPal8e889Aok9iA4=,iv:L5QXN1v7npNnY1GOQvZaYg5pIGQWM28aRdRKfyRZgOA=,tag:gggnalDFRFLF1N+cE+XdKg==,type:str]
dbname: ENC[AES256_GCM,data:B2AIDf83Dp8=,iv:ramyD13BScrc0jVaBFhF1GC3d/nitN2V4ZqgZhjCKkU=,tag:NrGkU9gYzOc4mIskgG2TtA==,type:str]
host: ENC[AES256_GCM,data:Ap55eiVmanVQTzNMFDjkxEQ2TW2QjfROXitkxbbJpH9lnlWEqNUfy62+xIAJ9ZJwR+MnvhM88q2eHTo=,iv:wMG+qBGNvXBObW84UbpbPYiOayjeo62Np/Hgan4gV/c=,tag:prWyOg8lTdPkn4mT5uKmag==,type:str]
jdbc_url: ENC[AES256_GCM,data:zbx0nmNAd/fxWqLBZNIsMbgCKB9Rm5lEgpR/JGtNAWQHHZquo5xjSs4sHUym9e5Rou4OjdLAs/pr+fZtgI9SmmNBjX7CguHqkvK61H8iHtmgkHwZM7BOMv20O9/j1SWiO39kE7IhdH17l2L2,iv:1/2voHWImS54BX99jNkZqG5JIuQikYwPmuptVYqO9Ls=,tag:9+aLwdC6em9wiM3YtyBkYQ==,type:str]
name: ENC[AES256_GCM,data:AiKT1gfoXyA=,iv:lWHLXHNHgIThLDYoR1/fL16TmfjMvccqyRKF6ou/1t8=,tag:02f9VjfLsZUSftAy79bQzA==,type:str]
password: ENC[AES256_GCM,data:/rJ2nqKPyX2I5bMx0EYCZVl+YmyxW+xy,iv:Mstha5NUhCwIJUNbGMg8fLnLVkKxhqCGdD2Sc36C6G0=,tag:wXqUWhpMZT8Ums/c1xb6TQ==,type:str]
port: ENC[AES256_GCM,data:YqbnieU=,iv:1iQVDLATtjhIbpgff4AHYLaghKBz/yn9hvq/GzciaHI=,tag:Em+PB6x/Mnw4Lk9qlR2Hhg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-05-17T04:43:37Z"
mac: ENC[AES256_GCM,data:Ya+AhSZyqjbSCa6hnDV48wrWfDSa0XZwsHWAAsJ97rOmZctz53Xt3EjfShKLEoAF3J9I1UtluwB3YZ0XfiQX5oJmwqKOuNZFl8EsXNddbljP+HzJaG02YwOfWhBGBvfYwSjXsd7EG97r7u+KjuQxI6MYY8mr6fdXL6hC5wXWOoQ=,iv:oy6zIvQ/DzLMeOJ47TZS4r4RzUVbOnHRGVxKxmuC/7A=,tag:fQ6oQpXIFQFMyK4DQLyO0g==,type:str]
pgp:
- created_at: "2023-05-17T04:43:32Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA82rPM2mSf/aAQ/8D+TfIfpJnsUOBeJVQVjociaoJ6oo2xbGc/B6nfxOP5Iu
Tf17Ab0M/FUwzCsQt65jxcO7F1i6jgO4R4xqB6vlj1y1a9tOvFW5Ky79zp2BEVnz
n2JQKe67P3U/heNgl0w4Cfda4Xyopn+wgXj4q2T4MWXxrP635QSu8NLcMpzBcmZB
3BVlwFfZcsOmVcglkiUaFozMQbm2aaUJUuQlE/T1aZCVoEnmFHbOYDeC2Hj+Ld2c
fRdR+GiM1GmBPUqdOFm3lb0uy5xwviLcoU1piQfxdxviCzGRFwYahcQ6JAFRcv+9
7nGEjXTd0RYM7AUMAZ2lwl7VUF/Dn6CYa0ilgqbOYD8U1x8seyjp4wKhQSohkdKO
pD4ZjGvF4VJAK0s4j0lmV1NB4iBlsARWHJDe5ImeDfZ1qRWtX848CdFcIHPxMwcQ
tKVpV3c89AMnpgrDQAF65OUk5N8WwNMtTteDQMpisrw5FUhlzqfhdqmx/L5qYzW+
QWQUVffDhA4RkdhD3xEiO8+Ds137u18QY3l8oUoC2bOG4VARZPxNugxZJw6wcezp
YmoSAGI7A2E72OMcgaV2LQeyBEvwI6RTEujQXzyvmGNpkLKEYjAM6ns+F8W5+qxZ
nFxgCuj+F6Uh9kGbJRXZFVOw7FHfujZxGAGbjPiRiKLjUr1qLhFrPkh4UoErNKXS
UQFXDIJOuD6FbKsM5igbpSltsFUuCSsr1bx52TlujpbRAbWP5NTJ3QdwrLiE6S1c
iYBI8+PnXIcql2nicv0aTZGSaDli+8RPXGPcZXDqU9Le2w==
=psjV
-----END PGP MESSAGE-----
fp: 6B61ECD76088748C70590D55E90A401336C8AAA9
- created_at: "2023-05-17T04:43:32Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMAw95Vf08z8oUARAAuUw8Cs2X6xRKGYjbIRfXlocUeW0I654rWYEYStFA4PVp
B+Wk5zi7UBvXx2lREapkjVYxwmckIHW4d+zxIiBb0i6ecLuOouUuQQZHjNY1MLNV
HugZyrLzOv7TftE1fdWvj/plu3YOAX2pMqPakaJ3BylG3LrOnJEcqtml2OXMEsXA
qS55r8tj1SiVYYiG1Dvqq3/kryzKKtiUz4HIojypASiQT6sS9mIpKWpGkctGDGUd
VrIT1tW25BKCqILkQ+41sZDRNe4N0PQUWZRD8aIiWI2d1AECkIHRLglC9O4arkxS
ShXCCXz1OOt/f9pbyABoJbWKZe5pcdeX/7glJFjxQ+hbc94jqKum/VaG0ml3GkUc
YUq4xfDMqxQz1QchLrAgaj1QCmUHaPvpxB3kyZhzB1CZL0ghvYxiIwALyvYQMDqD
EgvzoUh4sub++uGgXT0Lhfu68Lr5DpGc3FC3pzPw9jsnbXOnnQW5zQrnSODVMYMV
XdtvI67zJnJxgSRnMMmvAH5R8bWb/WT4k+ezTDUBHGC8mz+NnldGZWctQSUwCvoq
MygNgbuO35yq/R5P7ZU0SPQve+dBYxm+825CdHfQLYI0j0GLIb+4iYL4z5G536II
Tv/JpdPO+1PeTKkrgSvU2BC+8uyWHAPwAeYWLIgL9RqDlkF0jej4tHVOLOItvNvS
UQGoo0XiAD7eUVCmqMnAztxcKpyT6m+c3QD9AjKFEQ7Q3uTujEHTHNWfFlXwI5/G
ml/NQyHGbekl1nOrzyehE1dOaqfldFDmSjJRwWBjlX9ZvQ==
=NGdA
-----END PGP MESSAGE-----
fp: 88823A75ECAA786B0FF38B148E401478A3FBEF72
- created_at: "2023-05-17T04:43:32Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcFMA0/D4ws+/KPtARAAwoIzwkPTsDmWBG/FZ8oMfxlCIWFkGKlat8gfwuvkz/J7
hyoST5K4AcsyLBSEEH3VbTEm5ZpQkkDj7BjjNWvagZJ/swKngF2a4Df3YBeLIg00
z5M4YNNzr7LiP4wUUxSYsOp9TbraZk4LvkP6iyHnbHNfID0F8KWMskIZIdhXAqnf
mLw8Tqm7+8X81LRqpDHjRVuD+zocqmz3Q/PsTE5Y9A3hCUP6PiuPiL1Os4KKVz3/
r4Qve8F8IilCejGXIsWhRoxW/ng7naXHCA/yx93dFYohNAig8rZeVOxKwqlOYEWr
cfLs8L7WjOHbSJbxCPo3IJLQm1BcCroDCs2dCXSQZM5SSaasYOjmy1armZbXo1mr
xiPwblDMR9X1wE5rF8400P2haRNZ5B069B1L/bUV6ZGQndvcIkL/eFAxJ9mE6FbI
enwFzM7kDB3eFvD6WSAcisyLDECekW6VBEdc/GqT5cFJhjOHS0vXXSnFoSBYOSfI
cI8HRTLr/NQGb+F2Le9q30bvwfkzxDQMwA3XDlSt0aqronlYBqTC5N7tYYAZkbTd
ITzuNYRk4QlI1g5LaIYoePiuutvjdQ2aiHrk+UuezYVeGaR/payVtnYNCYiyByEj
y0U2hR1zqsGZ/bCB31Kxi1nxDPemNS0SnMDEFC5cE3dxk4Geb0dNgh3Pc9T60N3S
UQHJQYjzRZLZeOcM8fBVOzdZ0uU8qjI7FZb9lC92F4W4eoRjxdb4ngcNUwg4Z2cq
BhapahM2wSKEBuudGA8HaRVv4JqTDNP6aSl6BMQmEp1N8g==
=ksGJ
-----END PGP MESSAGE-----
fp: 3D7C8D39E8C4DF771583D3F0A8A091FD346001CA
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -0,0 +1,43 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
spec:
template:
spec:
containers:
- name: keycloak
args:
- start
- --db=postgres
env:
- name: KEYCLOAK_ADMIN
valueFrom:
secretKeyRef:
name: keycloak-config
key: admin
- name: KEYCLOAK_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-config
key: admin_password
- name: KC_DB_USERNAME
valueFrom:
secretKeyRef:
name: database-configuration
key: name
- name: KC_DB_PASSWORD
valueFrom:
secretKeyRef:
name: database-configuration
key: password
- name: KC_DB_URL
valueFrom:
secretKeyRef:
name: database-configuration
key: jdbc_url
- name: KC_HOSTNAME_URL
valueFrom:
configMapKeyRef:
name: keycloak-config
key: KC_HOSTNAME_URL

View File

@ -0,0 +1,62 @@
apiVersion: v1
kind: Service
metadata:
name: keycloak
labels:
app: keycloak
spec:
ports:
- name: http
port: 80
targetPort: 8080
selector:
app: keycloak
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
labels:
app: keycloak
spec:
replicas: 1
selector:
matchLabels:
app: keycloak
template:
metadata:
labels:
app: keycloak
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:21.1.1
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
args: ["start"]
env:
- name: KC_PROXY
value: "edge"
- name: KC_HEALTH_ENABLED
value: "true"
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 60
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 60

View File

@ -0,0 +1,49 @@
#!/bin/sh
if test -t 1; then
# This is not foolproof. Can easily be beat by doing |cat. This is just to
# make it less likely that secrets are output to terminal.
echo "Error: Not outputting secret to stdout; redirect output to a file or" \
"pipe output to \`sops\`." >/dev/stderr
exit 1
fi
printf_stderr() {
printf "$@" > /dev/stderr
}
printf_stderr "Keycloak domain: "
read KEYCLOAK_DOMAIN
printf_stderr "Keycloak realm: "
read KEYCLOAK_REALM
AUTH_PROVIDER_URL="https://${KEYCLOAK_DOMAIN}/realms/${KEYCLOAK_REALM}/.well-known/openid-configuration"
printf_stderr "Attempting to verify OIDC provider.\n"
if ! timeout 1 curl --fail "${AUTH_PROVIDER_URL}" > /dev/null; then
printf_stderr "\n"
printf_stderr "Unable to verify OIDC provider using: ${AUTH_PROVIDER_URL}\n"
exit 1
fi
printf_stderr "OK!\n"
printf_stderr "Client key (as configured in Keycloak): "
read AUTH_PROVIDER_KEY
printf_stderr "Client name (as configured for your application): "
read AUTH_PROVIDER_NAME
printf_stderr "Client secret: "
stty -echo
read AUTH_PROVIDER_SECRET
stty echo
echo > /dev/stderr
cat <<EOF
apiVersion: v1
kind: Secret
metadata:
name: keycloak-client-config
stringData:
AUTH_PROVIDER_NAME: ${AUTH_PROVIDER_NAME}
AUTH_PROVIDER_KEY: ${AUTH_PROVIDER_KEY}
AUTH_PROVIDER_SECRET: "${AUTH_PROVIDER_SECRET}"
AUTH_PROVIDER_URL: "${AUTH_PROVIDER_URL}"
EOF

View File

@ -0,0 +1,22 @@
#!/bin/sh
if test -t 1; then
# This is not foolproof. Can easily be beat by doing |cat. This is just to
# make it less likely that secrets are output to terminal.
echo "Error: Not outputting secret to stdout; redirect output to a file or" \
"pipe output to \`sops\`." >/dev/stderr
exit 1
fi
KC_ADMIN=admin
KC_ADMIN_PASSWORD="$(pwgen 32 1)"
cat <<EOF
apiVersion: v1
kind: Secret
metadata:
name: keycloak-config
stringData:
admin: ${KC_ADMIN}
admin_password: ${KC_ADMIN_PASSWORD}
EOF

View File

@ -0,0 +1,7 @@
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
name: ksops
files:
- ./keycloak-config.enc.yaml
- ./postgres-auth.enc.yaml

View File

@ -0,0 +1,8 @@
{
"m.homeserver": {
"base_url": "https://distrust.ems.host"
},
"m.identity_server": {
"base_url": "https://vector.im"
}
}

View File

@ -0,0 +1,3 @@
{
"m.server": "distrust.ems.host:443"
}

View File

@ -0,0 +1,39 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: website
annotations:
cert-manager.io/cluster-issuer: letsencrypt
external-dns.alpha.kubernetes.io/hostname: distrust.co
nginx.ingress.kubernetes.io/enable-cors: "true"
spec:
ingressClassName: nginx
rules:
- host: distrust.co
http:
paths:
- path: /.well-known/openpgpkey
pathType: Prefix
backend:
service:
name: wellknown-openpgp
port:
number: 80
- path: /.well-known/matrix
pathType: Prefix
backend:
service:
name: wellknown-matrix
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: website
port:
number: 80
tls:
- hosts:
- distrust.co
secretName: website-tls

View File

@ -0,0 +1,762 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFi8udoBEAD0OKIpZJ7TAqFI5G0x5AIX/0milJYZt9ZBfv40SBBm1ZgDg4iY
jugikXidxF21vDcj7VweY0DZSzsBsEgnFsRStSjAWUc0lVpIi2whJ0t4tXQJU0+X
qc4yb1IcIA8wsSgzEA/LRktL5AuvJbD8Y6jvFjzPryopSpZvFrydC+Ziy4THlh1o
lVAX3CfF9PgXF3P+XvFLhU0Iqo2bLChM8gUtwA7kT1+vaOXTaLfjIUsHDPwknoOu
qdLoou0DKWxcHd69riVoVveOhY4GnUbHbCj9LaRLjg8DSI9+SSM2X+YJ4scB2MCD
G9PtKIyAkuLjsZbg91hHFqRJyRPUZRxn6WR7waxvoKvxLanLJbTMiBiCepbRxDQT
r/hEPQ3tsDmPgg0j0ZO1FT0iLtjYm9gkTEIXiur/ZwGG3fqyAg0vKm0/crrBdLGL
TOGT4g3w5JbOF//ORfCcr1OxYtcWNiiO/hWElBMfbP9/iBXxZ06BW5Apc2O+tHQq
gwhQ76mKZNb2rwphnBt7Djz17vPIeqoH4xBYmo4obcvjMqlj8z2YkGSs7xj2E3hg
N5LHjcSJAQMiM85fZYmnP4Dlorz76qIkx+HXxy8V99HdFe8WFeeStbRywCjkp2RZ
YEZ0jVIS7re493VY+2f21lCIqMS0d06NYpscuxpDeEKilOiCkauC+N/odwARAQAB
tC5TaGFuZSBFbmdlbG1hbiA8Y29udGFjdEBydW5uaW5naW50aGVuaWdodC5jb20+
iQLhBBMBCADLAhsDBQkNgEknBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeBwIXgBYh
BD18jTnoxN93FYPT8Kigkf00YAHKBQJj0LldOxSAAAAAABAAInByb29mQGFyaWFk
bmUuaWRkbnM6cnVubmluZ2ludGhlbmlnaHQuY29tP3R5cGU9VFhUTBSAAAAAABAA
M3Byb29mQGFyaWFkbmUuaWRodHRwczovL21hc3RvZG9uLnJ1bm5pbmdpbnRoZW5p
Z2h0LmNvbS9Ac2luZ2xlcmlkZXIACgkQqKCR/TRgAcrR5xAA75FQNh3zbZzNpLcT
HZLF0Rfu9jR244AaLFcr+j7BLYOi3bRnukE1L1f1evIln1QVZQUTPuKgH4q5MApU
erIGDQ7pe8oFflzU2wRnpu001D7lbNDkNqHmEo0G353YbEe+QRcpgq0xhuW9ZbZy
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
ZG5zOnNoYW5lLmdnP3R5cGU9VFhUXRSAAAAAABAARHByb29mQGFyaWFkbmUuaWRo
dHRwczovL2dpc3QuZ2l0aHViLmNvbS9zaW5nbGVyaWRlci9jNWU2NTBjNWE3MzRm
MWM0ZDZhNTgyYjBmYWZhYjg2OKMUgAAAAAAQAIpwcm9vZkBhcmlhZG5lLmlkbWF0
cml4OnUvQHNpbmdsZXJpZGVyOm1hdHJpeC5vcmc/b3JnLmtleW94aWRlLnI9IWRC
ZlFaeENvR1ZtU1R1amZpdjptYXRyaXgub3JnJm9yZy5rZXlveGlkZS5lPSQwVjd3
MWY2X0tlNVpKTXUycXlNdXVBVjVSZmVadVBKQ2NzMnFiaksxd0l3RRSAAAAAABAA
LHByb29mQGFyaWFkbmUuaWRodHRwczovL2NvZGViZXJnLm9yZy9zaW5nbGVyaWRl
ci9naXRlYV9wcm9vZgAKCRCooJH9NGABypl7D/9k7XFqGXeKkqTrXrbAuf1I3l0z
1dWs8WksfsROqni3P+NjI8tdeuDO+7XRdhR3ZWdvHaB9bTuJ5UaE0p/Un8U9UWUl
qZBXgLuYTSzatH0Ln1f0poeYR2ufR6SljSCxKUEhYABmK6+mNcTmpD1mUINpmDce
BK1uZu/aCBVUVLqQu/epkEBTR915Q0imsvClPda2WffNnK9JTY2wW+GtBHJ3D6Da
FemqwVTX8rSG2Ms0h/uNij3wKX4UysyyWLYpRGUJuKVYH8Fpyijr/biiDR53gi2A
isydA428BMZqsPmQLcVOyV8/lS4qetXjAUZGgw67huxvPHJ67e3uCYgDue2EqPoN
L9Dlxc2TVVI3vTLBlczAvVw0FlMErlSXH39oyrBTYyIgC2vQlOmQq0+Eb/+m24QG
S7UvUAVl0aVzZYXpQ4MOM/0ZkK/5A7ppzpzn2X6El4ZbI8/5Z72q3ZIRiDixhLtg
NQlrA/cupYl+JyRBGD767pe79AMBplGuMN9TMR4ka1HIEMfnrr/5uQgrA5Ylq8jg
hBVqWFy9dVwD/+8f2R1Es3/vo1lXxywwr1SGlRaipt4jayUYb9azn5yE70k6HSHe
6aNkJGRcr/q8ohuWetdXEir4cRZgS/MeEjp3+N9QVU/hZLCR8cE/cIYXn9RE6v5G
RsezLdXYIsnDdB/WVYkDoQQTAQgBiwIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4B
AheAAhkBBQkOz3WZFiEEPXyNOejE33cVg9PwqKCR/TRgAcoFAmPQhNpFFIAAAAAA
EAAscHJvb2ZAYXJpYWRuZS5pZGh0dHBzOi8vY29kZWJlcmcub3JnL3NpbmdsZXJp
ZGVyL2dpdGVhX3Byb29moxSAAAAAABAAinByb29mQGFyaWFkbmUuaWRtYXRyaXg6
dS9Ac2luZ2xlcmlkZXI6bWF0cml4Lm9yZz9vcmcua2V5b3hpZGUucj0hZEJmUVp4
Q29HVm1TVHVqZml2Om1hdHJpeC5vcmcmb3JnLmtleW94aWRlLmU9JDBWN3cxZjZf
S2U1WkpNdTJxeU11dUFWNVJmZVp1UEpDY3MycWJqSzF3SXddFIAAAAAAEABEcHJv
b2ZAYXJpYWRuZS5pZGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3NpbmdsZXJpZGVy
L2M1ZTY1MGM1YTczNGYxYzRkNmE1ODJiMGZhZmFiODY4AAoJEKigkf00YAHK3xQP
/Rapb5NSCikCjuYAjCSVNrH7F9ufgJUGRQMPO5sCUsg/RQzNk6AD2J6Sw8A132PP
pg10wfxoVLhJVwwgHiWbXNwEbcQVQO4gG53LxlerLzNWQfbCQL7q46P0G9iAAmTC
h8pvTnLNaptWwvS1e5FQ9ltcuVtKaGq3IS3iLTfLQmZ1RUV1SZ6ND/aOdDAUDwuL
/ybHyqfi9qWJhJIFwut7lWEG1/nc2+gaFOPj+R4DCDe7cOo3hZBqDf8CrLbevVTv
8fCwuPyPIA5B/FQQxqxmN2fkbGTaxA6mqiDYFwhsyf6A1Lyw48CSFaHGowcSZ+VO
MNF7hnNHP0BOdE4dpZGCgUd9PbFdEIl0+fEfgDTsQYDNDSStTcRV0f7vT8BEXXnH
5gXi5gY41ShyxYgPWEG4h5a9trSy6pI9cjBpcx7fbEnWQ9qUCfG9P+bgQIZ/1osl
vIBnr+2Aa01ZzHsN2NKwDZOTaWJyzMrhK/VGsR/cqTVoU1RabmLgz1URTLJ04WOC
bgJ31TG9xhIs2XBthebSEFFpjJu8b1CWC2gypi5ZwHMjEYWJBodqFyngXYtW1oLB
rkdk8cxIh5e50MaYhPzoZpRU/vqEbcgWsQnE9DZ1t+cGnCRPPjVF3Inu6+Lajlyl
eCtA0iadi+D/FEbUEPylvtTc52pUo5/8sbe/F5wwGQHfiQNbBBMBCAFFAhsDBwsJ
CAcDAgEGFQgCCQoLBBYCAwECHgECF4ACGQEFCQ7PdZkWIQQ9fI056MTfdxWD0/Co
oJH9NGABygUCY9B0nl0UgAAAAAAQAERwcm9vZkBhcmlhZG5lLmlkaHR0cHM6Ly9n
aXN0LmdpdGh1Yi5jb20vc2luZ2xlcmlkZXIvYzVlNjUwYzVhNzM0ZjFjNGQ2YTU4
MmIwZmFmYWI4NjijFIAAAAAAEACKcHJvb2ZAYXJpYWRuZS5pZG1hdHJpeDp1L0Bz
aW5nbGVyaWRlcjptYXRyaXgub3JnP29yZy5rZXlveGlkZS5yPSFkQmZRWnhDb0dW
bVNUdWpmaXY6bWF0cml4Lm9yZyZvcmcua2V5b3hpZGUuZT0kMFY3dzFmNl9LZTVa
Sk11MnF5TXV1QVY1UmZlWnVQSkNjczJxYmpLMXdJdwAKCRCooJH9NGAByqvhEADG
ZDGHWe9Ga8D4EPdHZV3EErZOE1FznNMfd0yPVJwDaL2QKrGJfiCbld7WHHlkJBdu
12642L1F83Iw9R8PnVFnDTG2VBzUtdxXD+ogKqxqiGRfO9ANZHX0bQ++h06wkk/E
Q1dzoAv9gnc3tVKtqjHgSScIDT2QbSUypuK70tqLyZWv+hjpv6xlJYz/cGwbCSHC
11I2pCfRxMAKj/gY6jdkWbYd9/Ck3R0ShPy9E3yiKfmCrGxnfnTVH5nnS3WDaOnc
8eqN/DZJkixF/Ud8j2RqyCQByDYRLzVsJvKcXFWPWz4UDd2xbaQ3DqFHER2fyTlj
V7Vzf/fnMi23KkpnRB6J2lrFCIZzOQZ3moig67doazkZzLwEAow3rfza1G7xDULI
hpw6rn/BY7Mi9YdItl/wTx2Xb67WfCIWlEplpO+mm3ZCLxQgN//mi8xSggN2QLmm
9yjwEgrG4pFivyVldDwx3GrVteDi9sG9e3DZahVK6clCYwT0uT6IigF2WJUhQY9W
IPXDGIyDKXBP7pcdIwEnYXryyluG52XENU3p4lz9ECRn4y1abOsxdAMsjDLZTzU2
2/cNjE3C2ETFEE+ZbMle8R/mOzUGPxWOK+9jh7Wq5Np1pdKOW5H0NEhlJu1f7Ktu
gpZmAvEG8uwUiJFlGmTV/VYCCTdvogSSeegKyEi+6IkCWQQTAQgAQwIbAwcLCQgH
AwIBBhUIAgkKCwQWAgMBAh4BAheAAhkBFiEEPXyNOejE33cVg9PwqKCR/TRgAcoF
AmPJyHMFCQ7PdZkACgkQqKCR/TRgAcpjkA/+Jbmt7e/uKftdH/zOv6+ePkF0v+Mf
3UqQ+M5vEbuyF2VFXpmAmD+cLzdeuINrCNI86PlK8ZNXLg8p1hyIfuyo891+DVPy
Om1SiTwJAqLfOgQZGqeTtPFHbd/GO8sYjOmaauKUgGnwd7ZjC0l6pYIzXddpIact
feQfDFwhu0c45/0ki/kg2IIKo3hkOTpHIGDd2r6pUwl3RNx3yddyZq/SqgiRmGbh
UN/Pnoi06rls39FXbcFwBpe2v4Rt8mwd0toXPsUJy5+7suguHTuxYmw6fiRTBVud
nllziC3pOKWX5tK+CMbrbPGioBe/Z+DmpLhul4yaSNZIp5p3Ppw2TCsuCvySHi+v
d2TlFWn6QiWAz2eycadDUFUWfnVWuUMMp1BxXZuGWdXIVpDEgg6huzKZfeoG9uUs
0szK+QLaetcIGAqKYMAznQLa74F0Abi65fDd4GFLKj89lPVKZdbPrs5E5a/XzrU6
/PR0j4Cq7Gm5p7TgbBgNMXks5UoJsHVYAuX47g/fT0E9YWtCMzQqcXzY+eorzFBH
lWXxYUH/OpPnf4c7w9tTZYFxJAHGY3imsnzXe2wRZV7f5kELzTz5sCNAjwdIeKXc
GA0adOTtEMTpPo+2cjK4v6E+/Jouwa6YmlyBC4DjOMybRLGFxFMXNzpDSqdTlhhu
2zX569qK/kK7DbCJAlkEEwEIAEMCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIX
gAIZARYhBD18jTnoxN93FYPT8Kigkf00YAHKBQJiepwBBQkNgEknAAoJEKigkf00
YAHKsQsP/A8I5GignkZj6lk7iAKUIAm8PdqUv5eTfAHbxEC+KoPu6I+RTOvhIpXb
oWEhIChdnuA1WOhil2oTpIqN9SMt0TyLi+kXy7V8qnYvem1NUL/Uw0TTYieDb5Te
6BoUAMDDdMEeMTGmZXrGaAviX/GkOni8nxNnbf7oTjazvXJpu0c6ILMDw0k6qE8e
TFUvmqaQs8ooDoKAhnVZqiPZPzNPTFvVn5sEZG2Kvl5MnxWhgK0xR62x1UiDjwji
zVEbhtZmxz64zgHIHKE6fGqVOQso6WCuSvWSw7q8SkMhVxtGoMn9Xfj460Y9cLNZ
3H2oh36ZGnFtKTTvME4wCZc/HyNFv4/XCzalRfjxmdc8dDcqtZCSDFiN+dEq65Wn
9TQs6AxQ9Ax8lou067EikQl+UjBOWj1Zre+L1f8UtrXNHkdtpaKN3FSAI01aBQBl
rQKaLCF5VT/4Z/6liM5yExly5WZAKIicAvtESYpWxFeoKVAAWPDa4YmPB9iPYI6I
UMD0t5+TtX0JOdqNyO3Svh3GiJusuKJ84zfGT7eZaHsMFHuT3f8UcqPe2ZOGEnS/
9l/WYEuMK4sBrxVcYVTqpVwjBAUSiXYdn3t4v6flsVLIfrnl6PMrxpwyAxrn9K8s
IaAcI0UocZYplSPXy6bU7OfdNG2Sx3nOForq8ykLOpl+ghEzLzbUiQJZBBMBCABD
AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4ACGQEWIQQ9fI056MTfdxWD0/Co
oJH9NGABygUCXrgmrgUJCb3T1AAKCRCooJH9NGAByiCbEADkaYrVmwaKZokktGhj
X9ASBLJOg4BUO3el1auQhMTo3LmINOazD6kn4OFq5xBjvwniE0IsvPSr/2FhknuL
1iF+cEMUYtzg0pCjVR0a3Lj+o30Br5z5A5CR5OBQ6957cssVWij2Rn4jB5UCBXDN
amEdlrojh6yN7CdiF+J7CJcXkEnPTWBQM2E4LvOzgbRQ97diLG1LwYOaXaFKlolM
QUpZPsBF39qS3sGZrVnMkOYhM6D6EKTsGe9Z5moN9lje0lbFU2HfPTy0jlYNXIp+
icL8M8i3k3CxrhO781ApeBDgnInOHkt5rxN41cNK0F3UX8FZTh5Y9VF8vz3BEnd7
6Cu2e2qDcCEg+tD6Oz3HUYCwQzBK1SvKBV131oR5v3+MzLbQFeuNTZWGKZoloiZe
hzA7vmilTSlz7CUbjpLs1vEyiiO+t+TKpmpHcZeeWZ4iaC0KnSA3hqtZDu+yNHqv
zdE+fx01ZysMd9ew+Lo+MCZBY0uBnoHiXyfJ+4kUxgkxtatXI8QRzPKxEYzt7THk
svrK+b6oMIgaWUU5nsbKA0GMgVCbCsJkFo5YsbDrXs77kQ8Tc880V+7aANmixKVC
DZoNjOxasX1JR7odBlOH48IPrbZJmRGrsRtVpPn8gmHfA1NEjn+Hub6iz4FxGRBD
/yAvL2pxkT1Lgi8qAMk0yNLvwYkCWQQTAQgAQwIbAwcLCQgHAwIBBhUIAgkKCwQW
AgMBAh4BAheAAhkBFiEEPXyNOejE33cVg9PwqKCR/TRgAcoFAlr95hUFCQYDkzsA
CgkQqKCR/TRgAcps2A//csOcWj45ALBimTE+RmNG3jOJ/5E+v8D1XwEha4qnfr+D
Dspq6RFF2i4IWyBjExtbThKGtm8274554MkTKz7wPJcMUMJ0wOY4+o/jQUMDt5Hv
2kXWIRDfqLCFWgd4ou6hlZKx6b8lSyF5SMl7q7dsh7iQs+heVM/QsHe3DzKtgiRX
oyE05Xkwa+leoqf7gmruSg3c8g8YrqwFsZrRveou6yO2vJuTKdIWJwVVseM2GhMT
Wne8U0/UweKrxvhwA87M3TYNkXdWboRaXvqtsyXZLIEMo4a4jww0MPZo5n45OoeU
qqhXDxTcqwGxytlfptt7E/Q2lAD5Km+tOrpfy3XvIHZ02XJoZnScFYzfD55/sCPv
xxTzy0DpNlr8AqMyXYiznMXrH+yCPzRQ+Yr5tjJlIIpQiU80z3UORH+AwQ0CPqAS
7/qdxVpV/fXeq+ZG2KjfkozltBTmTkPtBT+iM8pVdaHuPpxMyf7CZ0bHAmC2/aZO
OV7J4yRHB+KF2TfOgqyjgBwicu1g3m7DWpuTBDC0zpycjoA4zNfvcxISkHbzezy9
qXEn7jPEFO7K/XPnp8+PEQYwYPVsU+MlvP5ZpmN40v3Cej6kyrfm6vivICpIVL0n
xxlmywhCPWBwAEbWVIpT0TfwJJVEPgdO4U2wXy1EN9+fI6+jT6YE4P1GGERsmiiJ
AlkEEwEIAEMCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAIZARYhBD18jTno
xN93FYPT8Kigkf00YAHKBQJYvd3TBQkDw4r5AAoJEKigkf00YAHKUEEQAOUTba17
6jovbf2/XZOYOzU/drE5Lgu7ajjD7WpTTqDHwJ+G6AfXFCL1gtwlxMzz+/8qZk1C
PfvFZPUUQVs+vPgKnzpegKRo7wMo9OR9sp6sY/Dxpf+RBroueKZLdMCdKTcRiz02
ODBZSaOQQIZXbrYho6BsW3ANf48zrbuObBVt2+7C9+HWdBjT5AIfZvWht1NDI0t+
Wm3ZMdBZJl8fx02SHLvNIBejy6dS5lkYiSpQxcoC4yNK3PWEbRr2n6aHyTlkL7Qx
ORTagxblQAOoeM2+ZO+twRXvAZgoH0FCHTlLz8CmoxQ/tgOPKWv57P0KgyJJ41n/
SmRzXiHatyb//l2H6FUEndCAFsOWfe8SrXFRBlkP4/b8A/qiQccMfczxjRW09mtb
kYZCWX3G1jXWJdkn2unOtDvjfHJVMsXVd1ZTHcIRZLDgpme0yeZFnQP/esmKHu0v
Roh8Y3x0lFkSv8I7aY2hf6xWBzOcVQBRn5FgaxRaSuLK6w1AFq04zXQS14Z/iLa9
GAri5eonwBSh7vL/rZysYjYQn1lkmCX6v3oELXBk2tD4Z2BgqS2tTv5GIr2U2Y86
96F8Wmj5LoiOe8MWW8JCA7nifShSEAYEzpDJATrvTu4nt+aTtnvo9e24oWeNZ2/X
0fNRjjFqTtYod1SfRxggPpnfq1+oFYXk/p3hiQJWBBMBCAApBQJYvLnaAhsDBQkB
4TOABwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AAIQkQqKCR/TRgAcoWIQQ9fI05
6MTfdxWD0/CooJH9NGAByj2kD/sHxFihX/kCFrDcSmjNV0cVOxiuS1gJ7iK/y1im
CqCHLbjWi7s89SqTs80LsbXCj0oxm2ApOzaarJoC3wLlH7pzSUAbHsC1vbJsCG8w
LSfKRDTKxpCP38pD2PNsKpZnyEeUr4ML2qhaj/PZrDlioLBCJhkGI49RY1Eme+t3
t3Bfp3oba2659mnFOl43I/l/FVVb33IILHMn6imySZv+HFDS++JdFcYs0svh/idO
UT6nIMp8KO/xY8xVbtQynD1l7EFku3acAxSDmElyN0A6SQqqKYROaemH2v6QEP8Z
AzPHNc8a2OH5q/ZSflGwAeiitAj1GUq6mVKR2mDlrLWno84zQmDQwTnHzbFXPTBF
fXJuE84mKau7bj6Lv7Pf9HpMg5dKN36I+nZVZYoGqaaBdWuh+cIdBlwzB2+fcB9t
qM24UcaKwjdptuUo7TcbQvMJF9TPxNmHbIihMdKvPlcHESWJ+rn+hzVpqW45pw50
dDSbqT/vAK7LvW/GglVEhhZY1IREKfNZdv7JMSod8u5AbQICP1dnzEPs7cc/6+ix
bbb9NvYh7amLHwHqXSObQCDiNHdVu+Pwx3iOiifF4TQB0P1+SWL7Mxa4TAnSVz9E
bMJP56/zf4r+0TA0YRvcmPHYhO/jOkaco60k1uWKmJpTYqEmBtCpW+0RPCrAq/i6
sb/KXLQoU2hhbmUgRW5nZWxtYW4gPHNlbmdlbG1hbkBtYWdpY2xlYXAuY29tPokC
UgQwAQgAPBYhBD18jTnoxN93FYPT8Kigkf00YAHKBQJeuCcsHh0gRW5kIGVtcGxv
eW1lbnQgYXQgTWFnaWMgTGVhcAAKCRCooJH9NGAByjpaEADBSQ5k5c3NdHtRT7VL
SHDE4GA8L0eMhP/zrI9P5dCv77L/NUiRO94Y6Q8oJ3grK60NhurWYHrbYsLZSWbT
QpTqD1FSuc4MHMzogk1Bzr2gCJowVCTCfEACm2ofabqyHXvVUYRhuUTQ/fVmM2ix
/zZI+E7A5uTTa62020AN4VpB4reS3tvhaDLcJ9Ih5bSNquk+7M2HZXNbSxmfSBZr
nvV9RLVRPy9/VDB/+U7qzh+kOr8Hn1GtteChno5MyDc+WfSwHUT8Ndev5Liuc+U0
Kq0vbMzbdZC2shjdBz83oVZ3lt8AotVVc/a3gIs8eqoLOWamrFQirKoeeb0EB8R7
5k6cQbhNDc/GRIhZVsYofZd6vmexkpd0wp0pCslfzxc4tnN7rYjuYmS8Tij7IIg9
SXAAOncIw2C14Gxf3uBkhZIc8G3WvHCDPAZRdpMH6hgPgMOzOVGadWng1mtKOx4B
bJZXZIVynC33//PDQWefGfuF33L8GMrrXDu4QfLXE4d9ejLOcPkM547NeBkajkSD
wRg3iD4OvFXMoN6qsrQq+NOtKi4VowY33RC7nvvn5It648MQ94G6OjWw74t00zsw
UIpoXaWqauDpLjLNpdaZiqVlTZ2ML1sG4SACKSU1kxPcnqCTLp6pguJMh6hHr5tP
mdoEP+cFIhMApoONXjfMM0F32YkCUgQwAQgAPBYhBD18jTnoxN93FYPT8Kigkf00
YAHKBQJeuCZGHh0gRW5kIGVtcGxveW1lbnQgYXQgTWFnaWMgTGVhcAAKCRCooJH9
NGABynj4EACnhPHA89Og84sQPNJzY1/J8l46TU3WGpT8qfhGkYXSLHBED+CM6axc
xRu4a/V0pKq5gOLQmT0Z/fA8cydpsROEdVUXruT8i3yZOGEXz3TcpJ3ZUcBrvCfV
Kc/EVdeCelvjOGDWUItGp+QG92OEQ8fweRYz7f/X3JVYx4N//P6H4+jdbwH64w1r
6gjjQTxw2aGRUHGqkQ/TNijaq+sudBZ1FCcY3NW7gUrqQLNTQ33tPq88UAUsGwl5
zu4PTLHP9dhE7WudQHwJZKdJJHDGb8C/Nkv69PuHh2M6VObF2ItOVYZ7JS/CqRk1
NoImVvtArpb//ZpcQ4Xzojx1NxG7wx/GqO3sygdlqBgFoxomzqLgMyO4ND4oBeYh
UFtzHlJtCuhpGMXT8o420bBfmueyVldHsNX/GY8wfITPOpkt86i1L0mg9t44U14A
fVbW8RBfBjzWPg6e8PTUa56msCZzrKiPb/etf409Wz9wVbJjFFnGh1XCZaDAdJqF
/uVtH3WRSGNjVW4dcwOJ+830cgzwvZRza2sEpabAyj4vEpP6KIuI2vTyKWpRnJon
XA73fDBAyO3Zt/Y940X3EA3/WZNM2gMWMc22E/ggAp5yJc68jJol5+xNjxYwNJ0T
J7HLosAPEJT68CM3Q9IEcIOQGSZ55mHeXVwc4BrL6puOeztfElISAokCsgQTAQgA
nAIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAUJDs91mRYhBD18jTnoxN93FYPT
8Kigkf00YAHKBQJj0HSeXRSAAAAAABAARHByb29mQGFyaWFkbmUuaWRodHRwczov
L2dpc3QuZ2l0aHViLmNvbS9zaW5nbGVyaWRlci9jNWU2NTBjNWE3MzRmMWM0ZDZh
NTgyYjBmYWZhYjg2OAAKCRCooJH9NGAByrAHD/4wuhLlbc1qP83E2fiZlOmgrSCV
GHgjPalrmYpdZs1v0HEiQcl/oy71TnXFQzXXoj1zQWuuyg5Sz+W2Ys6LZIYT0WAk
UXVDT451HMeR6yVmbDcvPKzP1mB3mGYUZDXN6hN9AgFHVG+AWhbS7sOHL2esTECr
2pcocy6LGXpmI1wv5x1aEO1IDvmPFg32YIOxJ/VB6JDy0piC9VwvGx2u0UnkvKiN
1CILvbUGpV68dOQG+ulAZGhqqU3jQPwFwntwBC2hAz9Oyk0/QFuUHfHySudjimO3
dMjlt/hXb6Dr+pw/nNcjLw+vFUrDEG9zkZRvS+1HeurkXBzatjftsn4taUZ5P4V8
ADeFtuTmkG2ocKD+bK92nqGmJQupyDq71k4Pi/Tp8OWJR04Q8/slhvg22HmKs8Mh
BrgG+cgRUbyVmOz+uY+Se/EgFWzQjhLkGpeJ9W45mIBVGKyrXMcTB89z6GgsgFtF
1EhqoIi52kxsBVivKNklLtzSzRbd9tSpiq46mAHAFQ72G0ptqCbBWU2gcVkBtmd3
int+c4+2nCgzisKYhaYvKXjZmoXXUOAqZ+SE9Tw7NNkosdSmB1QIuk6H1R7TChUk
Ofj4pGjCdtaSKyvbS/uvJzbr1csrhoaCDn2ql+eYXapD23Wve0abWFq2niyU4IKT
UAlEw6+tMFe5EdbYF4kCVAQTAQgAPgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIX
gBYhBD18jTnoxN93FYPT8Kigkf00YAHKBQJjychzBQkOz3WZAAoJEKigkf00YAHK
8BwQAK7uXVX+IRLSbOwSgQ/YypZKR0Sfqyw26agKG/38HrvM/8vGhVJIdpJfa1WE
anaKnkmENysJj/OEb2Xjeo5AkcohhkZDzioIb9yoOxS1KvHbhYyUI7L9koZzpsAi
8uKf31jLMXN6BovnPElVBEwswYhbCG5cCNpMl63/ht3hv77ufwbZXieQOAswEhYA
WX9k98IEXOS7wrhMXZO/09k1pqqMEcKfBtJ5gGX7r8lnAegKzCMafsb5rUyM5TjJ
EYRFYSzUWKmSMJ9zwkRGC6ZBurdIDjQ7y6A5O3uPtR9Y1EqBBvZvXUgYhAUDwxab
pDkPhjmrWvpt5o9NKyDTBSr/iGrjkb2wsg3Lc3HGBiMmDCvRsOyr1BtKVaKnWdyf
AywaFIKcEswNby0c2HoL2Y2IgTlujUAXaD3W6GtkFf1Hi1k0imMB7W29Wo5irUPQ
TacNpJY8z9auVake0gVMWk2BmAQoyz5gXX1GHjY7UPBl6srZ6PiOkPH7Lkyr5aPn
8qvSjO0yDnbbpQc87SEA6bzpw7YUcw61xzlHjDMYpkQV4dUqBigFhCr0gD+RT75q
ISZNTeTjPwjZEfHo3jJozCg6hRwMeMA8EcGpyhGRupKZcZKLMznNQZGwR7RqYyv3
QtYwTbWPUazqiNkcFxJIjfWX8sqjGQoCDvqt/i6Y+OJsrcAyiQJUBBMBCAA+AhsD
BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEPXyNOejE33cVg9PwqKCR/TRgAcoF
AmJ6nAYFCQ2ASScACgkQqKCR/TRgAcrGvQ//U0KA/vOKioVaZUsjVeRmFLYq/I3l
irpOh/2lSb/vNiToK3nYZWTVn3PESVos9hiKUOiWf6/fB1zvVq2ffDgPbKC7wj/I
dh14p3W/ixRb5nW/N2tpAUGbySceYJlTpVOXwTKJjwkgUYQUCn06QmKNI6YrkOCU
ZlJaSK1Ph5pltECDxQpPxGY2c5FRrwA8Lx/k3d10kR+3NB8ZckMPscxRk2dKu8sP
Z9zhZs5BYcsC1po2ZhxSt/335dnZ3Ya3hiVofWb4i1DZhAICRH/Zqw36VdlnjyhG
7hKav6VRpTZAkPNxLAdGaRfZeKVLMb4B3FZHoEZ4OpSh0pQ9T2sK8J+Y4gHaRvsR
oiUBmkUDXn7ABzXDC+Em5DCUoLOepQkMFmsZJxzDaUKskGfY8V6Q5q1eThSZjFtz
qB1OXAd36Y5/CeRx2erxGeuZZFJ+r5g7eNUaTTSzUxtScoc9arr5aAp1Hwv04ezB
9KIyL3xFpGMiw49Gg6BxDgaqbzi0KlfLBu3bEgXeB8smqMQ6XUtdZYBb7a+bTFiN
B/qVZoNUn2YjkN8yjl9GVlkxsom/9ksT0BlqczU6O/7rAZiNAnilIJu07VGxGnqy
zgIneL8JjydJgkwNC2yVgMue+EF1r0AGR9p0arjiTfzJPc9z9UcHuFpUEouHoYBY
PpnKktqSsXFP+xqJAlQEEwEIAD4WIQQ9fI056MTfdxWD0/CooJH9NGABygUCYCWu
iAIbAwUJCb3T1AULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCooJH9NGAByohi
D/4908e5KyeOxyQo85yO7Jdw7TY8LbvZppL6i0H3CimTQ8BNovwjCg/zjdjcyFQB
b/U3eNknULlxIzbfhlVOfXtUsY/JfpDCquBEJUZ9pQzk+KamWEujcYdHKxMEHU3Q
f7eF3bddFnroB/y4Qwq8l7TudnomQ5xhnJYTSkh2plhkGz60MK3jtUlFjK1Uj90p
qVbSMoY7HFaKH0+LMTP5i7kFCrYcyjX0lyEJvDst7rFDqxWevzWM35rCChMRjrq6
Y6sCuPW1OebH3tzmcHai0hpEI/tZ3eoP31wrVEXH7qfwwiDR6mwlZosriWc7eP9L
LZRFTZ0tJOUwC1x4FhPEX2o90GTWF6JD72I/8ag6BVAfmSf6V4KAhrKlHHCj3UXy
aB7tFgchPZpqh8i6jYptxrLF52HI6XV8LmG+/Pko/NRi7x4HHY8N87iTcYTTfl6Y
Jakmae0MRu21WvTGgUOZe70sR2XzvHRvN2oNzt2RgZqxDqjNzy6bJEHeYRCTJ3LC
ZxBB3JiNefzti/BIkBAnnXDRjzeLQR16oijceGuIhtWri40d/QCrNjvOcNFzVqHu
NHJP3tfBWxTjs3cxKzQifRmTeyrZ+/g6jKQHAA8hweAjK9G3TgXaLgMlUnX+ps/9
gJ0PsKSYaJiqvHVp8WGriWEpp/iV8s9t8UUIplBvZgbDBokCVgQTAQgAQAIbAwcL
CQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAFiEEPXyNOejE33cVg9PwqKCR/TRgAcoF
Al64Jq8FCQm909QACgkQqKCR/TRgAcokIhAAt5SkYPpCa3Nnd8FmVQkWQsIXcZjW
LadT5IzmUSXNFOTFe0ky+K7lzjJmt3fARf5TVWHE9NROv/sIjjoHUSI8zkX6b1yx
RjGQKRRIXMjnydeNcVtscoPlYWtTu7Gqs3WqSTF7rdwI9VUXuKqLrNdRgAyb9JOY
KPUYfmccDQiaNqliektXuPlVnXb2fE+e8bJH/CrvDd4EuizxDN1abbOhCfxjN9RZ
vdUCURiT4PCPscqFBFyv0jaPQFAKyF2+kCJOlqwxqn3YeTTTzick+Xunz0+aoUqn
ELZSlRZ9whASBXBD77u16zv2eggLlsnyEHQGtmOtgCmvgj4/OWJzw2mqlBd+xPZ4
EXya0TtR/NBo7LC7qQ8O1kbHwAa7APpd215gD1rMRDi3X9Sf374Yy2zUtTuBHbQ2
UK6S4ChQijv0/Oczy2ym+0pYBgEyocPMCFlC5XmU0p3vc93WIOpD/QL6Tsbl3KNE
JymhmUCBGUjx1FATUsAP68SADhxee5MzPgaUjiPtFz2rU0vn59PU39mNUFtWxj0C
kpCAq6+x4VoDBpHhJrl6m8sgolyL3jQvjc3Jg9+ZtqhauZMqpkP+heMDVDtkN7rb
iYNgwsKvXAqHs4Z610l3erEIjXGOHd5b4kDqzzatCfVQO1imbj2phgulYCyhTu52
8+/Jj9tAcIRveoqJAlYEEwECAEACGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIX
gBYhBD18jTnoxN93FYPT8Kigkf00YAHKBQJa/eYZBQkGA5M7AAoJEKigkf00YAHK
PZAQAIkm6ewnBkbvOqqwLvxLCa/CFxljMQ6Yg1xm+VfObznOULQXn6p+naQHXosZ
M/oRW3rH2YaM3BL3DT1uqLdsBOD93IOQ6JuutZj+4/xUEb0GwfpHmPxEvGKwU1yQ
aEzBnOoE1eDI8MF1ugQ0GlRXSyTgDHT1YUJ5kdYNWFOK96oL5ZIjQc4HsG7X0r8N
hFNm3AtJdjJDCrJHgsnjBLXKE8lEHxoCzCBEoOUvN88pK4qHaGlgnb1rfK9m7Y09
t00hyMYD20KG6GGiQhWCF3kXT1HH92WXVbV94WYfTHvz7FoqVsKilk2/OBQl5cby
37xlHvNbx4syiP+qwhjc3Ulxj0YSbMwFZDOSAJiYMYWGw0mVs/eMTcw9Q64GEDgY
lFltjw+OqugSsiSSU1wSKI1Ctkl/5rhXNbc8t6MqTE1o9khQgCc6aUJYWM4ysaUq
GGg96QcNx4pMtQuAhUItRLXEdqvxnX5EyB9kMU0VB1vt/9xMY/8nP4IGc0laoRB3
D2km4pxp9ZD5lnx97Xahn/XrwIkBK1D3I0ZRp+dA1Ae4MSBqZI+XHO9Htvs5dwOh
IpxGucGadnJp7Atm1tzLzrV1RvcjU6+rCisjh8hMEumseDRLoerPlZ9NWHRNnCNv
iSgCz4jiMmpVE1HaVfcfRH7pYEO8zONmjLRzDVWTg+eBfMi2iQJWBBMBAgApBQJZ
jKdIAhsDBQkDw4r5BwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AAIQkQqKCR/TRg
AcoWIQQ9fI056MTfdxWD0/CooJH9NGAByubyD/sFkNtLNIViPA7QvM3f47mFuF/t
KWaA5gIlCtX1hWmMWmp+JpEOopgCkhDZVEUFCo9yqZ/l5KdTv52tcGykieNKtgsd
UMnDaVUoR+MLoXq1+Gsf+jiNPAFc+ZOqgqX4MGakRu6S0SYs/Jz8vAckEMbeG0uJ
g4b2Tvg+1tCE5Ag1J3QYqsaMW1XRQqe8hOye5h5VQ8Zg8Z1coj4wqgM8CyC0O++a
xn9yNUXNBKQwGxUc3dEnuFZCMR1bx4XUUkLU8hxbsxn1W0+nM6ZN2p9jFj6KnGko
YbPQvcRf0qMJMTlMCMO2aphXPK5A59mJSzbNNHKhSbAhFamSIwcrWPxLryalHEtQ
bN6AV6WhiijCa1jNOiXoR1WJxBS2guE01OgC2+eHoiMUyuzmb+nkmGo8sKFSkb21
5vRhWkhFPlsELT0VJFyVuteB5srlQdLXbIi6sAT/IsZWU/NpQpPPD66tM3JYNCR4
UjnD893ORI3aUyTMjkvYZzXONYwAqUZtHvwwAqk943qkeLNVfAUv0+WQK4XnKbdW
q6DrIZ4UDKUnsuGBaNmcT+dizpaMtAmVUgQ0lYdEdfz+qXcUCe6CkuT3U60k471x
hTRGbYASMbbyOZ1ce5kgWS7knCkX62kuNYdV18vz+sIVR/7QtP/4vMBhhI1FQalW
dqSxskjbchUuYUD5ubQiU2hhbmUgRW5nZWxtYW4gPHNoYW5lQGRpc3RydXN0LmNv
PokDlwQTAQgBgQIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAUJDs91mRYhBD18
jTnoxN93FYPT8Kigkf00YAHKBQJj0ITbRRSAAAAAABAALHByb29mQGFyaWFkbmUu
aWRodHRwczovL2NvZGViZXJnLm9yZy9zaW5nbGVyaWRlci9naXRlYV9wcm9vZp4U
gAAAAAAQAIVwcm9vZkBhcmlhZG5lLmlkbWF0cml4OnUvQHNoYW5lOmRpc3RydXN0
LmNvP29yZy5rZXlveGlkZS5yPSFkQmZRWnhDb0dWbVNUdWpmaXY6bWF0cml4Lm9y
ZyZvcmcua2V5b3hpZGUuZT0kblMtVnF2S3owY2Y4VWREX3AyejFwVnRrVFFwNXUy
SXhmRzZrOFBCZ2JvSV0UgAAAAAAQAERwcm9vZkBhcmlhZG5lLmlkaHR0cHM6Ly9n
aXN0LmdpdGh1Yi5jb20vc2luZ2xlcmlkZXIvYzVlNjUwYzVhNzM0ZjFjNGQ2YTU4
MmIwZmFmYWI4NjgACgkQqKCR/TRgAcpE3Q/8CZ36kXGZ54z8MXWSq5joN4pII8nN
38MpZN4QSB/lzMrdhrkGb8WD+wzOaff5Bt4a7u2l8Imx36f/CtbsEk/ig8J2bpsG
Cbvnon2zPo8aKFtOV35kfEHsqvCvy6q9fPpEF0MW37pdKsANVjusAvaT8yiFXsW3
8beaE1naWX4Bx0/kb7ERIIyHLZW9sS6tdCHM9fHmujeMItwUPtjMRGyHvMXTXYAQ
mkovWEUKf1tVc06KNzHx3LOcAowt3R8/YwtRxCMNU5oTFwfi9uxR1rsqb5urjwbI
N3uD40zfXP9UWz+GA0USHYymtoR3+kB7sZXLDI1u42wJcVVjEfK5m2Rg8hoKseOz
uOtBttVP7zcTfRDj2Y59G+dYHPzScwmvA/8JHy2Mdg8vcWwHazypHgA+E2R1Fgmp
uz6zLotGife61jy/x7g2y20UWcbogUCLpZDWW5tgzbpb0+jZQ0LRLNNxz3VV9apc
DVAfPjE03e9+xMgtUHSiT8MBGjJ5OWz6mVt7j/LAxL3LVPkbCYASjZAfVecXppdm
MvJ77RCApRB3lMbaOF1WW8DYIgDLm+8Drz3wT8xpbPxCFdvTH4UQLO8nIB9UYYaD
Bp3/YLLRpG4nJcm2CywDot2COq/MP8xYnHgM2frk759Z3gdl5F1IEBFE2NcsEUTa
Gi+SGZYCwcfxi1eJA1EEEwEIATsCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AF
CQ7PdZkWIQQ9fI056MTfdxWD0/CooJH9NGABygUCY9B0nl0UgAAAAAAQAERwcm9v
ZkBhcmlhZG5lLmlkaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vc2luZ2xlcmlkZXIv
YzVlNjUwYzVhNzM0ZjFjNGQ2YTU4MmIwZmFmYWI4NjieFIAAAAAAEACFcHJvb2ZA
YXJpYWRuZS5pZG1hdHJpeDp1L0BzaGFuZTpkaXN0cnVzdC5jbz9vcmcua2V5b3hp
ZGUucj0hZEJmUVp4Q29HVm1TVHVqZml2Om1hdHJpeC5vcmcmb3JnLmtleW94aWRl
LmU9JG5TLVZxdkt6MGNmOFVkRF9wMnoxcFZ0a1RRcDV1Mkl4Zkc2azhQQmdib0kA
CgkQqKCR/TRgAcoa+A/+P7uaM0Yna66tHAhd4Y7myXXGEpR7W+jgG0UX5AgduoV5
sS2E5mSXtUROgsaNUqrHZjq4L30Yk+tEDD/5G7gppg27Qtanl+tfArd6NCHFOcIf
O61tUcS/tl4EmZtWRCUWjriAI21cwzq/0dxbCImEYxX7kCC9ZvSStAlRUeK8HkkO
tBUYOU9GzDQyt7ZCCfGZe5gJejqqET8I6K1/wn5ys6vCL16vsrnDSwRH0BVUqcy7
daY+pzhtKkkWTIm2GTs2Wqpykeo90ILfVx3VTYRXLXvuBAWhzFnldw1pq5Aqpo2p
dNPjw+2eAkGrCgelivrAYTEoJUxjA/4sxDhMfk/lRWXjt0+e32/mwNB/9e9R2ms0
C8cq2J8rjkfYYu0YtDPth+K9pJEI7ZV/Yf/v7R4CvToLDKzpeucLJsn9MPmIkYQj
wc2iED6NLJsYBYcgir057q8CZrfEUarIEaC4Kus9wfhxk0GLM7+Jzs8vP/qkwcoE
ur2vdj9h8nTgdzFBAjkE6a3AHxWls/OQ9Lpbmp4NTofsvwriAOPHVpUVi0QWuaaa
VAF+eclu1nvnyNAa8i3w87MISXkEGCc2ErZeKT1kedNmJ5GBw5kPdlgj+dh5m8Q0
bqMo4mJr2cVVHPU9pM6CsXha2D1MRYrWrazOyB0lAkLG5g/P9UumzD0RGqXQYPGJ
AlQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQQ9fI056MTfdxWD
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
U+pVYGFv4IXQhLs=
=y6JC
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -0,0 +1,582 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBEoE5H4BEACwigcH2W+tLHRC++V0FD6ppThtZCEBPo4Kf595N4dkOCRzqZrn
uZeokptTFdb2Xcsi4kQXfx2gTsQStri5P8nFywG8dTniful3BNuLbD9WuNFhWkg2
TZx64BsJEzBOBeKluLsiN0IpgAj1KA9PGBNU7U0DEGEsw8HVGDcUVYhg/gVcWQVG
O+Z1UYLpdws9lmMnTwg8KVudjL3YcUB/ybsLat4qfhsH5hjFsXQwwlaNh3GlDpkc
qldoZ2WjYEtw/U9rZadc3HPYvRp4keyb7aGfdGDgDBqXGbtjdHvM5sqiQHgWaw9E
RcUrICsZX6vS8+lLx+TLjzX1/bwNgtOVmiBnnWmcB+JDtTNWI5ux+6F2vq65IXXV
1m0kPZo6B0w0yYOayOKvgMXtQ0hNuoRZO41tO2W6P114FwTQIKNwrUh6Ypb1ty6E
Sp/hHDPUopcSezpt1oS0IHDOKVKoUBRkN7rne+bNUtQ+O9hEyZlxjbFnSpa6KzjL
A4TB/3qm6H8pBgbzqyQQQOrXK8qFOpRYk6lOXdrFwFhXO28GLQFkNk3wWnBrTp0t
OBj7RA5wL8BTEWSwz9aa2dU/SdwExRxxbzweMbJpsaDdtu06njLUXNQvA8aMiVOI
NG+kra0Kkh/jRdTxeR2dg16qqBA2rwYwnk5vQ1WzFcbep6gfUpyWIbdTNQARAQAB
tCtMYW5jZSBSLiBWaWNrIChQZXJzb25hbCkgPGxhbmNlQGxydmljay5uZXQ+iQJY
BBMBCABCAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAIZARYhBGth7NdgiHSM
cFkNVekKQBM2yKqpBQJi2L3ABQkatQzCAAoJEOkKQBM2yKqpsmoP/jN9YEa4c0Xc
wFpHYawCOSF1Kj+2g++K/DrekREO9EVBNY3ZFdkHm/ahJ+Ku8RV9S9YDFnGuh9NS
jNZdqy0P+Wbb2V0A75s7YbmUOIjOYa8n3IepyWG2eAyTDXlXTU0LopNOoxNXlf5o
d3X6n0vL9nQM8AnFNJpAZNaeyACmX5FgB19K+QErDkEcurxGhP+INl1JHyEPz/3f
tpsFpeCl1NSYq0dVSpIAYR13guLG3iFizoUxIv2wZPFU1SSbvqAPZYP0817EHm0G
dHfdRqAlW7ICTZ54+4oxuuwvToQ/235ZOzcyecJvBpaMlHG9N2ZPrnUxeFOg8iFA
+33syaPmhX1k/g461y0Fd9BwWLCMi4bxg0loFUwpDh6cYZpJDt0mzH0vP78g3neu
TRepeg3hisYGFAhTqRQ2YH4XckYbEtB09EcGTLUBlZnRms/wmDBi9cdmiCH3BU2g
ac6cljEedL56I/5Q19lZJtv0fWLI2iFGu1M7QE1lZ7rLCNiYdiLd/i+1VOpmEgoV
WCnBZtRUrZTVqxciqAko5wIYmOYHU0IVjMQNrV52tg7R3wD/XiuQOxkit2979y5o
wjkYW1wlBTJWzXZVHxAl2zRSNA7q/GDoyyb7M0LtK2UOTQQc1wKajvtDkvcLZiQh
j7jgzvf/lBfokenU6aITrXWgCUS94dUfiQJYBBMBCABCAhsDBgsJCAcDAgYVCAIJ
CgsEFgIDAQIeAQIXgAIZARYhBGth7NdgiHSMcFkNVekKQBM2yKqpBQJg9yyCBQkY
03uEAAoJEOkKQBM2yKqpcp8P/1nk5XjktsBeAlmQ/3NKg5psX4i4xsOxG828bPY9
EgRuKEjiOrlhDGTqDb1GhuS+t1Tyj7Yh0T4fIGXd5npzsg6HikUJ/4+w3TME07Ac
ptc6W4nZvgdd2AHd0oL5tqM17IxPVxON/xKZ1aLs/YhZ9r/Q/0nnLpavQsY3hVnu
55ypK/UGbsnl0heVG86mkBzXSqyidHWyzROPaZIP7xF4c8izZelYrzm38FLgc7CS
6PcS3Q3rIp7aMnMFsNa63i5eGBvdKD84kzNYo0dTswwXc7iwAhotm2eOK1CeAMlq
RT8TLMENZI9ZkrZuc+OoqIL+1yz0+uUc/R9Kfh4kTEoQjOQBf7XAl/diDehK5bAo
Kb+pprL5FjG1abCe4ikrm7nVr/y51Zn9cGzFRW7vd3udnB55jQqQP4crD2lmOp+2
K6oJQj/vnOExm2htuYU9jRM6rhZrur8svdw3CKcBMfQbe4SlI2w20Ch3qrVe7r0k
kEyVeBBRGNCDGqX6t4Lrdq3odc/ElkLxJZX2oRPbxLW+hPmkz6PYlXG1I4F+dkfL
WQGePDx6Jx4aqPiEnhbmAW2bfftMAagkNGzn6cGDvrISYU79EKPJnrsUlIsMkQhT
aW4usO407/pd67iAp7pGxaHAEF5glhEzuvIuLvHL+Al4rTYX+RR6Zmgj0Ty6HFl4
I5sFiQJYBBMBCABCAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAIZARYhBGth
7NdgiHSMcFkNVekKQBM2yKqpBQJdJfq4BQkW4306AAoJEOkKQBM2yKqpDBAQAK4r
JGAF8/3Ljd99lPFkhF1J8s7itYJZHlkEINDvONp5Um5dAVHk4QuxiLg4ATXb4qnq
xo9UZ++m682VYN+ursEgXqm/uL90oAt9ZPKvHbkrRCDTuljHPg37T1nluZ8vZH4D
T+8wSg+iLMSsRutbNWCHrRGt9D+//j29BqnDb5Xjh5AiQluFJTAUYwDWoyKyEmUT
MybRQMi+cSKXX6Qu23lETbbihxNRbW0TQ+tQ711wMDyDUo8FAjKRke8pTCA1LQ2P
MxdpS0g2k1id/kVWj7JZ5iRhKISgSa85JoD3fipmp1SWkfv9oVEqRo0lnBYG3PCF
++M2UIS060kJ17cVvIzBjN6X/jG2TUxdo4lFP3/NaPxiccUgU6+eH36Zm0J+RGet
3DUBqXLEnmnHtLubaHOnkN1rducWBVYGIw1T07PGQCQwTGgk6mI5u5f/TxZBdAMQ
NyUZuPuVNfF9axBsZehxL3YTTjnh54N85diRNWfmW9ekldt5jW3mzt175+MQGXXN
EmJNTDKdG1lg35Ay7UGJnAQ0G39+Riva1lijs/BK4Gm1RdgjWqqluOgJFGDFfdGl
s4FSnhBYDlFWbSPAdPlMrTKr+zdF3I3gti8YRu0EnbTEVTNfqOSKsLImfvk4LMHi
lFJghrM/1SdRvJQWDOVgd6wI3DRJP2aROyiFgQ2qiQJYBBMBCABCAhsDBgsJCAcD
AgYVCAIJCgsEFgIDAQIeAQIXgAIZARYhBGth7NdgiHSMcFkNVekKQBM2yKqpBQJb
O6LiBQkTF/HkAAoJEOkKQBM2yKqp8N0P+wQsf3EPiR95LHlheJrreoEhkpeCrLu2
m7dHD83+khZanhOw25GeUU5annXVg0pFICUYdHFqYjlAXULI8gDS193GaP4lCU/N
92/byesCk67OLANBpW9+2WEEKdVMaQbs7Z8zurx+3OQmm1OLfNPDTjkDbKBGdEuz
XC0JSpH690aa9rAO0K+t2+GLaOoBO622KBXtbBRpIUnPDu+UN6Kl3qCNBAEX0EoZ
Jt4mGYiM0rBKrlmNwxiPY9FvjChjVUSElSbMIr/0/aUBWXYS+CeRvRVD3ks7H9sC
dcmJ066O1HuZPFs8W6JBD40+UPZtqGLokoabPJbn1v5N8nfrFLemIgtRfdv/t7p3
6rWsSSQLYpdNWQf700YtHhAi1+9ze2jj8j1PtJalGRdOIilsfugKp+I7sU01T50P
HnYGGwEqYCSkE+rnwUl68/kH7+gkK1xaHj+LTiqwCcS7OxZsVNGpoEKH6gy1Z6py
h5dKuJgaRy87t9ram0KJC0O3bEBvikrCmkRJphdlJBRrfKkOEx7x8O7jbLn4zrph
U09xkcZpOrBW4wHpRf/fOQVI8xk5NNwECSqnGkRpIfs8BdH3fmY6GCiA9x2uxXMH
lhCuSqBfUJMq6GLMx8HMRARU3fsR0HwGTZc4aNxFVnzILZ1aO8mzlw93/1lpG4k6
nqwc9HNT8uk7iQJYBBMBCABCAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUJ
ETZ7chYhBGth7NdgiHSMcFkNVekKQBM2yKqpBQJZWjCIAhkBAAoJEOkKQBM2yKqp
ZzMP+wf3IM4v2Zke5qyMnMZvA6Vii1yq2q/Nqtv4aqv6NfhRz2XsNl+BotEuxMR6
6aEuI0FwQhvUBvORM2HJzz3kbRAx1d1ICG4G8Tq4dHqjAg2lekpotTavLqh7K5Im
kTsQRvgK9+7Lq6e/UnaeSZwioxiGFAovrE+p36tKooZSKzUO5vohBL652oHb1jiX
AwoIfng6IfVAew4zQKwJe8IVeJfthk7XG7+4YVmO2H1F7nrfWRIJgR4OtarCw+3z
VADln0HwyEK41kuRjIpvnsRFTAWgSZO9PUGalBI54VL9dvT2EZXuPaRFbV90w/HE
TVxZybALstU59lEOCnpIpjQix4+iPn0ke4Wl0P2X95j4On/fFnDhJpO4DYXQJOSr
ER/kC5fOQP98CoKNQu5dvqkuhzPcinkIANlrbGKP2ltESkIw1ZBIRMWR9RNvxx6j
1F2dWieCPtCmOZ/bR08zQJcXbjWkMSyyokXBv/YD0UC65eCTG1nRdWEOJq2kv5qc
k/CMXSWufGWYEfFhIEM1RWs+mJA9UkHsmgy+XSg8wwYv6e+RaRw7zZW9OrJ99e67
HMVVY+FtckpGHebeLaAQtneZsUYyXW+nGSBygdwKMcLgu7mWogR8RANqEt8gy5sk
RBG8VhLs7/0yifqaGrfx8onSzhYIOhVHSQUUwqXAAlxT9hXIiQJBBBMBCAArAhsD
BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAIZAQUCVj/FJAUJD/1HpgAKCRDpCkAT
NsiqqaUGEACHcGjGTjXU4/hFyr16eaQ4RxK5Gcr5QKuYabjdyHPsFQayCIHh6lVB
HHeYFjeiNozyGe5Rff60+vbR4l+ZzD3dFf6IlxqMrnrAyD8WI7WZkew6uFsa3Min
5pAdIP2a7kDDLBVO1RTMYbFN1yaa27RFVRfPOly9vJej8amtAJGWB3nWNKIsn+MV
SEWo8gozpnPqWGWc8g4WuFdbRCEXiFqqnB+n9+TOCZymr158tqFEEQEO3StoyWHw
qkpTvyYBZpFM05uM6BqUkcXlwq0fGX4mJADYwMfSvaDFjfNt+3/+N1wtnWSgkpFq
ZaiSPSQxJpTo67ZuHwn4439giy2NA7visq/QnJDeVj6VaRaJo6Nk1ThlGGr6hnPt
/lQTBchkSVTC9UMFBCzcO4iAVn/cufmODaldQFLiqrnI/frIXqw5TqpShj/h2y98
hnqTM191bdzzJ4QNDcv95TAX2UYGrvNWfm+my33Wwd2WNmDo+hDVBPFP9rRZT9un
vJwIsXCScXdSNtoW8r4Q+4fjMnVIRP7QUV7wfdGxQ6du4IC3Hxoc0xPEOP2of5TB
RiPtZPNy9bT29h6/aBXUlk2tZKzxwhXzV9Nq4WXZTrmU2NTRZnVJxXjqBaIALgrj
LKzSvaA5yjWxguhQajeH2t1ZtidYhAkm/7/FTivxyO/CTTBywRnkcokCOwQTAQgA
JQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AFAk4IrmsCGQEACgkQ6QpAEzbI
qqkUQA//dvj43bk8eazJ9XOMcXpTMCDFTVP8/yqfBlMZVDrv0JBzBesfGAIjlVfu
+xAf1GjZ+AiW17rgr6bbb/yQBtT6ckK3yXArQgWRzpYISISFFGji6ZiHPYdVOgeY
p3Vy4rCe4QIJD7gUFtbND/gaXf4v4TrvkPZ/eAkmOioYRoLEuTvIVk0xda6HR+AI
fWrt6RzaYxIG/APlTae+WPEg4mh28mVwbhVeNNBi+W58Kn9IHhBu+GC/wKv25BRy
jE4M7pIS7Lxn4W/pHaF3XxPAuAXkMkWdPtzf495jTzW44WSd26mMwSdASHjEwm/T
AYD8w2vjA+baDwwCG3/lMyAPQGJKU7hHhc/e6cjm/Icn8FLo5/aiNdny1vr8NoYR
u2qEI5z2cNM5p35sG4IJ1bWgAAiWjr8tMHTkpGFgadddwMN14j/ICd2Y2AdeyNF7
kvy725FO21SDPjNQlcs0ckMxQLk4gdvB8W59TClbHSMhhgDnBu7XOWFjzpNqrFau
UoQKtS7Qekyn1y8CTpaG7ougD2iIxVLpUcgAOzc+FV1VHCoD0aDmG1JsRqt7MPpQ
APHkF+PUQdRagspAmNusJnwG2xh6QkXqs29YtPLgb48a1bQMZEKpJMOBpYiCwtEU
CzG99QnqYkd8xG5kaKGc8Uy2vUu94nbmjelRGlbHohEqf89u2eKJAjgEEwEIACIF
AkyvVWwCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOkKQBM2yKqpuTAP
/jaBYWdj7UbiGZ81Kz8xrYRMZ/KKcrLhhPeBpaZbtjdJRnr14Kr450DIYibJ9tTw
87sK+ZZ1gR6i21SWAEz8hqoBNzpz3Kzh/qZPIFdkHDjyLmBTdr1IBioaOzggTiON
4eHOWXSSnpHLbKim9lrs7LryKeq+R79gnWOwYUq67AraXJeS/heUD0kzaoIi1yQb
FrpPIk86mbJ1TSgE6fJ8PG4l+UEO3BZwMTdHLSy0iZ8czJZA13N8hxils70VY36F
TqQicBeKwt88aknCth9qcdFUpueG7TjyCK+gysgxcXe5PhV0LL7Z3pO0UCXCCnMt
WEyh5pDUpbQWSUe19mVTaWTtPeIxNRfo5w6lzSuTYNizHKhITY5qnqvo9kfmzwhR
3gsX2A4SCsJlPdp0kBvtXR/FxYFwPNXe/u10xcoFnOZ8JEqMjDv4ckKr5L1N+U+r
hdPfuGe64AI7Ouwxi8KgWxFeQsT4dx7teASxMb0US2eJkzrDzH6WXECzz9ez7s3v
mqsQBlwjFDGigRJRLKRl0LCOiGYURiC9tUJbAFi/dN75fLrfO0NJJsZCgekm0XjM
wRhRh5HBOBSGI8mTZREaeDW6ku//rG/xlRlsFXY9jYIWjSKG0RUdpwrtA/tdJctp
GojZAhZ24GdaHCGXR+3PFx539MSXYHgaPNC9XeYF9IN5tChMYW5jZSBSLiBWaWNr
IChXb3JrKSA8bGFuY2VAZGlzdHJ1c3QuY28+iQJUBBMBCgA+AhsDBQsJCAcCBhUK
CQgLAgQWAgMBAh4BAheAFiEEa2Hs12CIdIxwWQ1V6QpAEzbIqqkFAmLYvdkFCRq1
DMIACgkQ6QpAEzbIqqlaAw/8DQBbYCnTxZ1mKmQDS9eaDS+sO8rFsy2qOkwMhS8i
ehSYMj/SQ5SqnjVVgxMLm4Wk7YN7KtuoA/mdkopHQUivEaWoOSuvR2AlzgldFzHa
wfC1IxbE6fyZXcC2c0vnDdShB0PfwiYXtMddXz7E9SvzBsVa+8BiuIufP4B2qp21
l6a0nKJ+ymRD1xHtWqvT1Ela++qfJMrjdhuM7Sv2IZSe/YY2+gUBNdRH8O10173p
Dm1jXKMsfMgznPAyZKFQwwojR4tnCVpgrXiegEvIChTr0gwxJ2U004OAmqYXweMp
t1svBPv/fnKyCG+jrxJ1h59+ZVwfsCAtNtLbFG73s4ZwWI5nnlyzJuy5kRGcLIfO
vvvsqQM/d00wAEmMzb3C/+uXzyBW5Hgg1FLY2CcbxoUiYB+gqJ07aTaoEDNQm9Gq
kWZY0+C1qV36q1NRyRFRMhmL7B6EJ6DJU+Wb+P/XiPohbakS32dCOXCIbtjdy7uS
b1YqDIglshz+Tbw5eJD8Fn11GvkUhDGTWzbL9UFdExTZO580A3Qh2UtMCRQJNu0p
eHwljyc8JJIapMEXlhi1llwQN+ajtPhYkvmhljqWFaprlZPPpfjuEdQQNcvnqGFx
T8zGIdyu8kEailpHxf291XSG5sLfzmtf+/rwAU2WmLD3DZWo6BFTagwYEFHH3UZg
HhGJAlQEEwEKAD4WIQRrYezXYIh0jHBZDVXpCkATNsiqqQUCYmRlpQIbAwUJGNN7
hAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRDpCkATNsiqqQQPD/0eX3PgaIQk
BgFiWbO8yrHaGni/eUoy7bVrIOiH6i/wOF4gKSoW8IpScMf6b6I92DZsT2ltYjJ1
RhYxj5mzwhx3A4JSilDw/HTm4YnvzHoADYJqioHkZRZJdGshsi16fWzOvk8T1aX3
hiQD85PYsmTJNuLxpmzziHRnuYnrP3EBwsr4TOXlHLTYOun5GCcnfq/M/VdVz5DR
pcPj2+ir4ZW45V8+bcFuIqZkrLGVPuG2ECvKMWbMrN/CwOIC6gR1u9SFiOLhI2p8
9dOeYjTE1WFxEiSr0wsfFk9Vd4uk6DDU+WWjssPfaSyXJdAJZtRg19PYJupXHJRG
P20KS8t2ftHyIll5hPIJI+CAmKM4IRhXLxl7GxMttxfJCl2BnHz2VlKvprJ2922Z
V9UFyA/CxgSo2MCBKZZT0KdN0FLsBi3QI0NH10j5ctnWN0N8MznY03FNEHBUt/pX
EjaeQN9ma5Qxmqut/OpON8/0A2z9HyU0KhGcyfeE0LN1skUdVJKwpGyY3TOe6+Ls
Hd8iO2DoMR593u9Uxp5b9Y0LPZQhOf/WQ3QoAQGoOxG7owKZiUa7asUiTdvgLA0w
lpyFttSRMot4BQe4yqqfOOz/ksZXyNv6LOs3jF2t0vzO5r/paXdAk6WuAmG5qMOr
c94oXWXw1WOAaS+psmYeIL1R2N2yZv+BxbQsTGFuY2UgUi4gVmljayAoV29yaykg
PGxhbmNlLnZpY2tAZml0Yml0LmNvbT6JAjYEMAEIACAWIQRrYezXYIh0jHBZDVXp
CkATNsiqqQUCWash7QIdIAAKCRDpCkATNsiqqWfMD/wLMr7VPNRl7EmECc5tpRyX
svX3A9QnRoUZxOWZK8BBzMUH1h9CTe0ntGQ3Xt+41N4QzOYWXloYOLIwieOBNjGf
iLbSMdVFkBR6BuYYC1YW457XccJDMdYATbhPtOVL8jmg4wrhWcF3NSgPwDZ8H10b
3+trf1vWLk7F/Gz1pGu8f6DQtDY4PlV+QmJ87coR/uKwZbZ6YRX8aFNefp1/zsic
Is2fy63ds2rHwWx7BbBuzfvCThkvokXeSpLuJQwzm9NnSrMnJcWc96VdefNESiT+
j0UhZmtcwUmNSmuKKSVBvCVBudmG+1m8PUBG5TI15ExU5W9k8AJ60CoAw+/xrHiW
9Cibcf00JjjbnDg4jpPXFm8+Y+R+joP//MHTx5yRSqdPx6nq2/D2dXHGb0uWwUT6
Kfx+zE/BApvCqB5rpDfbOYgrON3YORYiijoaQnukYa7GJrjyBQnGXYtxU1Vf65xP
C+WdvNntTn5JuDVAyEuEIJ7LVaW8bDJpCNzLbelHOgtRVJeQgcJj6FtHbblG2wk/
QbJV/IMUaoiGz3tIJZHqZVt7GMbCI9MalL1X0B9B+qPt50k/CGdc9onkrXRW0Azk
NPTN/V1tQ78am7MP3OiC8B+sxRxW0NFs0q0gWhTwS+uWiGiT16vAwww507jeCqnM
E8djc0WfefPdoEvfxAIov7QmTGFuY2UgUi4gVmljayAoV29yaykgPGxhbmNlQGJp
dGdvLmNvbT6JAjYEMAEKACAWIQRrYezXYIh0jHBZDVXpCkATNsiqqQUCYmRlIgId
IAAKCRDpCkATNsiqqWTqD/9N/d4Ln3u20PlpqXVymUEKrQ/iKxe9YnpfpaXpdzCQ
gTBoNnjVK4Yx8BgxekLWasmalpxSQQr0f/RffwRcjLZdE//UAPxEORBeQw8psQhS
O5YVIavJI/jSV/9Br0nGGLqFfDXq1QFddwdmuFYIIK1DjuAwJOMHIUe+DWFqJtUb
J0dvjHLOiWmcUXj1CUJE97f8CqNA3+cdgLLgQjJXmPdJCrqm4j6BoriHH4eXYam6
NZOxnFHkNL20e2CmJh8duUUpowE0x6XNNZw/E8z2iUXaxBcqx9GIo1fZjfV+6vov
PV94QSs6eW06oLmuYobS5MgQk/b7Oc2F6V4WsEob2nEPMJ7lp4Ir6cfQ6scCrKd+
7+aZUOqz278DOgtsmFsFmeQOnyTbVCdl37tw7IdctHTyI5bksdjxD3KASOOS/17E
mX9T+4VvA8nNmZqZ1ADkJp3odKLG7jKOB7W7U/l/ULtYlN0JSXgIgJidXY1ec5FC
3NGMf50FwF93Atv1XNO3OaN21Sdcx/Fu7MEwmzFens5F5mCIeKrTeRNL1oPNWTBc
9W0rrWIagHEjs3ZKJC5tFLXybbwhCuShRGLCpmJxfIgTF28jT6JaT3nZW11pwZt+
FluTGOuvlLhOmZQh8yF01SEexgK4lOWQ4vKm2h8XTGRjvmKr/g89h2ltS/Hll93V
L7QqTGFuY2UgUi4gVmljayAoV29yaykgPGxhbmNlQGdldHBlYmJsZS5jb20+iQI2
BDABCAAgFiEEa2Hs12CIdIxwWQ1V6QpAEzbIqqkFAllaMCMCHSAACgkQ6QpAEzbI
qqkXbxAAmpYWpysXbcIKPSS9bYxwLPdsMmRb2LpIY8AVmkpprZduRr4Itg+YHslw
KpIPFimup08Sla/C1iVWYUxqWfss7XfFwfh4/GQOUQbx3aqtuRsOLtaIUjykT/jR
uh1a3Fu3elEnxtVqjh2NPqFPz0GQlVzUZwY9R31DeWNBCUzG8kPK8FDc2D1oV5Md
qLch7tWwwcpv+bdn4u1lpJtfQ04BUFGNkLHCmisZYHe8TvhIDmib5M47sv/S7Bt7
nwh6vYS/ncz7AqAAFhL9dNJRfB4VE2WtiJNJvYuyWupmSSSLvGtD+imxc7FdjODK
MeaHN/LqAOrbohdIihsJDGkcioTi6ckfcgrF6vknYlYv7LyM/b5RPLJq58+5Rh5l
2YWMZycN0TtqD6tuAWg5WPgpXm+QwhgwqzsDIBgFBnOZSs+Nsl04xQACtKF0miWu
Vo2mocqiAeyXGFOdO4DipRaPjae12XOmIfnQLszeY3D+uqJCJ/i6rMJCBlWZN68e
1BCIuRiqprmy/Tk4cRU3m8JU7HPx8DZBcG+jaZYbq1a6uIqN0tAL4SO4jfNwmMP7
bPhvb0gLKWBLGWHOZhCvz4cGEEJVPxlJuV1gP0+l6sJIBMy0Ii2/JvPdTTWZincV
pgOZZGss1+o2bUK2FN0FXbbIuPQFzCjCoGjIQW6l1MbSd7FHa8K0LkxhbmNlIFIu
IFZpY2sgKFdvcmspIDxsYW5jZUBnb2NvbnZlcmdlbmNlLmNvbT6JAjYEMAEIACAW
IQRrYezXYIh0jHBZDVXpCkATNsiqqQUCWVowOAIdIAAKCRDpCkATNsiqqQkCEACw
Od5nt3qGtfLjaj/BRe+0Ep8PhHdX07h/Hk7z+u3sgtI1aapMx+5Sf5nakd20J3Kp
BKKzJwsO+5zyvL9u3BMI+GvkPottO+caj0srLa+y35Em9ydgviKEpWtWoM8xuGkL
kGCeA4O8IpH4ws9LEqLhMoYgFFALaohITx0vVosXwcjkmir5OOQXS7PqD3QDJa5c
bTrFxGDwJ44LERUZt9qrycT2pedeLTnxx+hMiAJXzSsIXDh+KxKNB5rztyqR/goW
EzXOUeQRyCU2D7JNnAEWRi1IBbEOV/CGLZA35zD7bMobwXGQNaCL+Hs+fnWHCcSa
FAq2vt3efUq5lgseZFEC5XJrJCsROQ2IJ/ZoRN7Hok79OpdMlxp0HHfuEOG5YKgR
pwy35kKNgFX6mfyJW74fIjIgIYB069QIYZykZbjNUpIRSye2S1b9P5UDJww3vGUh
L0XNc9JwutjWijeNr4Gpsv4Goreee7vip5U4VOrOUuOn4819GQHORmVZPAnB5QlT
xEevDvsBirCIkwaV9bS32+0WEXtU4AwvTXLnuySAAl6FLt4y85QglxNugH347UDx
BkQghjlaP3AER7V7hOOwXG6JrxoJR/7dJ6hqHrtH8V8fkAqjsx8XB8/IALdGBKfW
64e43PhjCDVi7zCmDdFEP2IjmDWnvrQ68lV4HG8sMbQnTGFuY2UgUi4gVmljayAo
V29yaykgPGxhbmNlQHBlYmJsZS5jb20+iQI2BDABCAAgFiEEa2Hs12CIdIxwWQ1V
6QpAEzbIqqkFAllaL/wCHSAACgkQ6QpAEzbIqqn8OBAAg6lfQrIA0Pmf+kQEjMaj
An2bWmfoUPBMG1liiBDrR0CnGQN+A54Z5UIfT8Wha0qvdYJh/JrWOYSQ3w1lMpDu
6QSb9mKxsPKL7HsE5RGB5zPQBJPgTo/Plurek21IxDWMYKi0/L+Q8RvWQDeYPK/V
FYDOSYHLoDgTe7c4sV990uSnkBJdPD/+3dhCQ6mW7wTvJ/XP6QKa+5+J71jEByIW
RJshYgbjXrOZQtn+74ZOCC1pOlcyVrhLzp2anRVFbrMMBRJV129zS8k+B9401haX
7SvnmL1Kfrt5/tOXRakdv3w7Sc+WdopuVChFzhxsHt90wyW8sowLjndBbEQ8g61s
JGZTJaEcK7vzbO/h1T0WTnxDDn+wKYr2lx+0YKry06iDmVbdfIQNOAXskjXLhDQz
71nn5rsfIzhRnpyQaoRsl17SdL4nodaojdJbntb6/ANflvIklbYBqNP8zJhXdLC6
BAGbvHjdntfbfZePJWBZEhBkDdHjXRKuRSPrnXA5yPvLs6u04QFzN0RDy+RTshj4
TuLd3VY2b6bM8EBIBHgsE1z8OkAyIwHFSAHR1frz0e0n6XgJgGACvbToF9c/8jMW
Dw6LnZQP4qPwk/rHFCaCGlPu4uPd4f1V1ic+HndEuGN2GCuGt0FI2C2ZDZklHhDz
afUGAUAmvNJgbKYOzX5uCb+0KExhbmNlIFIuIFZpY2sgKFdvcmspIDxsdmlja0Bh
Y2Nlc3NvLmNvbT6JAjYEMAEIACAWIQRrYezXYIh0jHBZDVXpCkATNsiqqQUCWVow
DgIdIAAKCRDpCkATNsiqqYJgD/4+vg6QpffzUEe6cTX5cZNb+FAAdMXcTYe69hwb
IEoFwRE2lKDcgqzbSuyOTeqBeYYIdkIcjZC/+o6mANWSmF3JHfOAz39zQ0/kW4ox
je5b8UKwMBbr2jun1RSVS7qGlZ7wD8WYKTj/S3Om9ASCO9VHgSjMtbwrGTa/3a/t
abhM47zGAIY0sRnKve4f1I1kjGix5y/ErYr4D60yS0ru0EDAT3rpymgdMQLD10Df
DrrIaqO6bTk/ZR2TACTFB70wRbmV3m61CmLNqJjzxcs0yX/6FHR3xTLzmFyY57xG
cyRW4yTfWHS6zxFugzHDF8xwylqszpqM14yeD96oDvkMPqW/vE8TM0yeqnwK5ugb
fxFUIECwOvRN5gfz2oZYURSssn8obQFn8smj0+yD2xUNjzR2i4xuTco875+QL3AL
RjXL5IlKJzMk5ipzYg3bgL5PnLGZ3NBObjAW5rvb0+oLMS9+SvoHlvx5EkLJt7Wo
+s5X9Xd6apivR6WRVh6qmAZgKmh+0gcKu/m0aIPJTUgQyBLGRRKBqKbU4RmF5uJn
7pFxjhnLsQ2Xh6ZIUeisJ4otZkBtSO51WbRhpEuqADbrPWqyS5OaMH3eqQCfnO82
LQZzitly/UBrpIiJ0isYM3bgKyAuozXYVXBQ5Xx9lYvvvu8FVluzwarEfZ2zln3U
E8JdP7Q3TGFuY2UgUmVhZ2FuIFZpY2sgKFBlcnNvbmFsIEtleSkgPGxhbmNlQHJl
YWdhbnZpY2suY29tPokCNgQwAQgAIBYhBGth7NdgiHSMcFkNVekKQBM2yKqpBQJZ
WjBrAh0gAAoJEOkKQBM2yKqpEV4QAIqMAvQx+XsJoe7Shl1Ormq951mQPy8IS1QV
pNg2m2bMybPEkH5kNyr/W6dGpLsjSsO5FoRwZyJgYM61HYRNYq2bX+z5zGdJ6gc+
p2Tlkb9QEkZNZh9CHJmWReGu5qPavQArQkMhQQUG/VE/gYAUfkihYP3prm/lZd9w
kHf3400Ii/a5a+cZKyCxGmVMgYbDRqhSu8Aal1acud55ZRicZwctjllUFZDhQ73V
MZgWRiZp6t5iCLNZ+jauI9jI/Pann9o7ibxMnURVfgGoRmWDhDdNvFOVSfCPUFg5
QZvgg/zA/6meqZNCPc1g84PpC9OY0SAaE85qestz9PsZoo24FPL8VVap/dZV2Q+H
qSIIyBvoTkGHCkspXCz5XoQ805Oxllc3cDJHog3286+KmfynIr6hwJAttPGR94CE
NouICr4rtY+zTtiuS3g09NE41y8uDpnDzogd4J7Sxgq/uMvgjaJwu70Fz08e4dmD
luUIBvakpHXY0azoegAv7Alxw5tE3nsR9kYS/IzEdk5EMPoxSVaY6dEYp19gU9jN
7CcofK3XJDM5fByb7VXqbnPJRPeFSdF1XANeJffzeY/MrExK6pl1XPk3czi9YUBj
GNL1zBXHf9IoJ+bkNvx+uwkZeUDllWfzRR/4i8aGR54HmMjL6+vy4NJz7U0FdAG4
ou91fitD0dc61zgBEAABAQAAAAAAAAAAAAAAAP/Y/+AAEEpGSUYAAQEBAEgASAAA
/9sAQwAUDg8SDw0UEhASFxUUGB4yIR4cHB49LC4kMklATEtHQEZFUFpzYlBVbVZF
RmSIZW13e4GCgU5gjZeMfZZzfoF8/9sAQwEVFxceGh47ISE7fFNGU3x8fHx8fHx8
fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8/8AAEQgB
HwDvAwEiAAIRAQMRAf/EABoAAAIDAQEAAAAAAAAAAAAAAAIEAQMFAAb/xAA2EAAB
BAEDAwMDAwMCBgMAAAABAAIDESEEEjETQVEiYXEFMoEUkaEjQrFSYgYkQ8HR8TNT
gv/EABcBAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAcEQEBAQEBAQEBAQAAAAAAAAAA
ARECMRIhQVH/2gAMAwEAAhEDEQA/AMR7KJQEcK2XaCdt17qpx7LLSKUWR3UF1IC+
yAEF1kGrNdlGTyoGeUXC0O7rvhSuqsnhEcFF4UnjCikEd7Xd1PZRlUxAK67UgKFB
IvuuyuqwuvKDrXLr8KeUHcnBRxyvieHxuLXtNgjsgC7sgZfM7USvlkPrcbKiMjr/
AIS4dXColL2PNONLN5anTTky0AoQMLL6j7y4/umNLM7qhpcSD5WcX6C/Lz8qQof9
x+VFkLQtP2qxp9YoUlw6yFe03IPlRYcZlA44KNg8oHjBWG1EjrJKXe6la9wJNcJS
R2TldXFDnkqYQS7PAVauhw0kIi7uKU15QtRcqjlwXUpVEd13dTi1ygisrqx7rlKC
FFZU3hcbVHKKU91ygg8rhwpXIJzSEqSSRyoKGuUOHUbVZUj4XA0VQuYy00cIQS14
I7FMzZaClXZKirSc2otR2C5ZUbckJmP/AOTIpLM+4Jll9RStQ2zsokUsQSmlhtnk
zDlpH/5KpduvIWpqZ5SPVDttIEPJJpdXGKKKYixHlDTr4R9gOChfwTRhF24UDCnK
qJXUo8FSg4Y7rqXKduclBFLjlTgcLrQRtPC6lPKkBURs72u25UgIq70oB2+MqC0n
hHlTygppRxhXUu2g8oKfCj8Kwx+EJYQqV1bmkFKPaWv2lNtNFDKzcQ4dlBQuXHlc
stLIh62/KYjB6uQloz6wfdNR2H2VKsMtzSGbgqWHAQz8LEbph5ifMPUHgdgVTPLD
GRUQd+UhA8MlJ/20jed5WrNqc3Iv/Uxf/T/KW5cTwuIUjgLUmM9XU/4XLhjhTdcr
TDuVJq0JNruVQRK61wCmvKg5dVqRngKaPfhBAHldQ5C4ua3uSVG89hSAs+FPqpVk
uJ5KjKC2j+y7sqs9lIa48AoLB8LiUIaRyV29o/utAfPso+UHUFcLupfZBzmdwoyR
SnefCgPzwECrxTiFCaO13LAUJjjPYhTF1VH94TMQp5tVthANhytjBa48nCzWotjd
2XTZagjJBRyH0rDbNB2v8Kxsob3BVc4AdQVdErp65+HOoHDFKaS8Iqyr7wFZEv6k
mh7oRnva7uuH8qoKvClQMFSDRyiiCmwOShN1jCGvKIPqf6QgsnJKnCINc7gcooRy
pxVqxsQvmz7J2DQGSnEtaP3U3CQhtc7gYU7Gitzh8BaEuizTT24JysgMIfVEEeeV
Ppfk3pGifUsgZta53Bcm3aIQy7NS4g3ivtKzxK7e0gU5h3Bw7Ldl1UeogAkBII57
hZvVbkZ+r08emeHMBfG67vNFIQwdR3pG7NEWtJ7g2GSJ/q9JLT8ZSWmf05A4ek+C
cFXSwDtOGvLbIxYvCN+hmY0PADhdY5Wm4w6iPcGkH+4HkI9PLujc05o4HlPqpjBe
1zHFr2ua4dioW1rGs1cIA5Z3rIWPJG+NxsEgLWs2OpdRQhyMO/KqIypa4jhQXWOF
GURc1wRPNx4KoCkONKXludFjI0nKje3sFTuU3lMY0zGQQSEdqmE+k/KtqkHd0QF5
UNHcow0uPCojgY7rhzhGQ1gtzh8IWyNc6o25vkqLBhrnDhSWNZ97wPhXfodU/l7B
3AulWfps/IZuPyp9N/NQC3dTWccko4yHOBddD3oKh8EkeHgiuxVkTXDI7KXpZz/r
RiYJBsiDIye5FfyrBp5dMdpaHB3cKmBhkw57ccAhacReAGubuacc8LGt5hGcSxvD
mU5ruQRwflK/pjNK98lM3jHhbhhbIwt9IPgLMmieyQB32j00U8RW3Q3JxV8Jl8fT
dFTR6m0R5KfhaxmnY9xuhlKn+pqbaL2mx7IQBbHLDI1zdkjAS0+ccLJlh9MPAtq9
Nq4RLE0htPJ5HhZGu0x6odt20KI7ApKtijTuuJzHCnN4NZT+lZ/TZvYA68Ef5Q6f
TGN7nPG4FtpmSIxx011PA3NzhwRGdr4zFP1GEttJvLZHeo0T3WlqpmzxjdzXNrOe
NpNYA7rSUpJG5ruxvuEII47pl7rokfsuZEyUEVtd/qWpWLCoN0Ci/KN8D2Cy3Hso
28Xa1rOBAXccotpJ4VMxde0A+6aYUNLsLqyrY4HOORQUBQD0lMNYSpbG2NtKuWRx
aaxXhUG+SOMCzZ8Kl+pe7A9LfZV3YARttuCLChIgeurP7q+CPce21CGtcRtBBWtp
Po+pljDtu1pyLWbXTnktFAHutzrrjKfg0sjzTJXWFpaX6MxgaZcnutGDRshFROLR
45WPXX8jId9N1Tm+tokHvyqD9PdG7LC38L0wjcO9ojFuFFoPzlMZ+2BDosbq/KcD
Wsadv8crQ/StF4r4S0308kW03/BT5T6lY+p1G6QFpAI/Fq+OtbASR62mj7qdT9L3
Alkm4jkEJXTOdod+7ubo8I1idW4wPaGntx7q3TyxCRr/AO4c+6oh6s8pk6dtGbck
m9QylrRbieAhI3IdaN/SkHf0E8FTNtmeQ4bbFJPTayFzOhrWUOz+4TMrJzHUE0M7
f7S404flAq7UdOSNjhiQFpPghKyah7o+juBMZtl9x4TrGB7DHO0bwbsG0tqtA539
SO9wzSJjP3+ruitrrBXOj3c2HDlCI9vke6qY4Q7nc0FcGbWkNG5xUMia45JJ8J6K
AVZFD2yVNMKw6OVwuSSh4CjoxyPaKI93d1oy6cCIybXEAXt/8pSGZznDpv2A9uyu
mOk+migGPDn+TgBZ8+k6TqBBPdeiETmRkuIII5xSxdW0bzj+U1MZojYzgZRWaoAA
KAe/Cm6XVyQ4UL7pZ5J/KZcbu1U6EiNrz3Jq1KKBaJtk0VzBbXZyr4I+pLQoKWrG
l9I0H6iQFzto9uV6uECFm0vsAcnssKF8ml07emI3Hua4/IQv1cup9Ln23wOFiu88
eiilEzyWn+n2PlMigFgRzSMaGCzXBB4TEermJDTfypqWa2QQpDgkop3HDv3TAdau
s3lcXICSpGVxCrJWdpcbWF9Rhdvx+AFvy4CUMYdb3D4WK7QlGZf0oY4iPtXj5SsJ
02nl3Oe5z6xtHdbkOhEjXyyeokelp4CyDHHtk6gcHBp2Bo4ctTlm9/qqb9LqGhzd
4J5JHCrb9OkcR03NcCcZpaf07bHL6iCNtOFI3wNOoMsY2C8AcJZhLaq0X0tzDcpA
9mrQkgbtwFZHdC0ZyFhbWLq9A2U7gKd5Cy5YHxupxul6WVubSOrgsWMLSMnTxPfJ
taMre0uiMcO559XlZ2maGzNJNC16RhY5vpNhDcKiPdGRzYIK84dOY5C1ooNdwvUb
em+uxWLrCItU6u5yqbro3ucwBpoDBas3XRhstd1qEN6e9oohZWrlDyCeRgqIyrtd
390FlTfC7OGrGizni8qTcsjWYFAn4QNBcayLTxja3oBjR9hvObP/AKWa1GWBQsI2
YdbrHwuDQ5pvBYU39O0x1MtbjtHKlrcjomiR4Yxr3k82cL0Oh0bNHHvn276xXZTH
p4YInbWgCs97S8DJNZL043YObPACx66eG5p2AFwDWgCwXd0EUrX7T1BbgDQVWvhE
L+m0l4a27PddpH7XRutrsAkD/BV+U+mgWPYNzbcEcWoTU0LIx1GHYO47JJ7bcXt7
qWYvN1oxPBVjyKSGneeEyThNYvP6CTJVTmu6dAWVYVO40st+K+tMzG4D4CpdpWyy
F7xdm6HCZ2AlE1gC1tT8Ls07WCqFK1rFdtC4gKGhqguUqDlMFUgFJaQW0pmQYS98
hFINA/UNB4JrC2mM2D08LGcHCVo97+FubgIATzSrO4GRxMRPjK839Xm/5olp+4C1
vTEiE1y5ec+rxGORl8uCq5+Cimd0wLwWkrLc8h5vg2rJJCxhPnCVDgfu4SRm1U0P
ONq0NNoGObumlAA/tHJS2mifK7bG2z8rbg00eljEmocCew7LWsfJf9HDHbiHAVgW
qHvueMAYBtNOc/UP3O9Mfk+EvP6ZA5oIYDwfCzreFpNK5skjuwOR7HumdJJ+nNtA
o+DympowWtNdq+QqtG0NmoAhwKWtSHWtl1Dd8jiI/wDT5TH04tgc416ic/CtZGQ0
Z55U9E3bVnWh6wRaj1MsSVXHKr0+jDTuLs+AmI4z4V7Y65Kus5IrI3Ot1u+UMnGB
QTBaOypkFNUqxVCfXSd7JCM/1U6DYRa680pAVbjXKJrwiLQFO1SzKJakc7f1WQV1
IyopMXQ0ocPCOkBwlWK3iwlHYJTjkrKOVloi++obGFraeNz42l+cYWZI1uTmwtiG
T+k0eysZqqZpaQ7sF5n63N1NUQM7BXwvT6yZsOnfI8gAD+V5SeE7DI4Dc7JKvh/G
a4kgOJ5OAp2dMbn1Z4C6RoD+3gHwrxp2ni/kqsnN7dINkYFtGUB1HVdbm7nDjOAl
pGvcd2STkqyIOw2vc2o009LOzmUAgD7ncBKauePUz7NOCW/6j3Vjw15jiaLa0Z/3
FczTsZG17QSS6kF+lAmha3/qxHjyFAaG6n0+bVUpOm1xdH38d0w+jKJGkU7H5UVo
RkEBXNCVgddJxqirGikYGULUYwqlERQS8wwUxeFTNhjj7IclIG28n3T7GYSMZLKP
7p+KQUKSL1qHx+VUYs2FbK8VZVEeq3P29Nw+UqTVsJLTRTBVF5CuaQQqz05T2QnC
Hems5onKtyPcgecI1FRKXkyUwVQ8YWWyk3OE9FrIGxNDnAOAqu5WdqHAE3wEq7qf
ew0AMKpiPrf1F00jYWAhgyVQ/WQu0wZtBk7AJZ7Oo524+r/KTeHN9vdaZonus8Ub
4V4ka82+93kJRrjef/auYN324J8og2zWbyXuyfZWWdzvVdkc/wCEtE7+rnsj1Fia
QcepRTjNSGyNcK4RmamlwBABsV5WYXUL5dSZ6ojha0myeUDrHDUQlpNStNqGanOx
5pwzSz4pzHNvaSSD3TTozPbtpDubCjUa2lkBpaMbuywNDJtO159QyLW1E6wCgcaj
AyqWOyrmHOUKJVzN3RuA7hWWoJRIVDOpHQOUERkjftd6grXtolzTRUxWXepGxH1h
Fsa3IGUWEJdkgozqC7NlGHhUOFqGg91AzvFcoHkUhrF2oLxxyqIDy054VvIVbW2R
hWhtBQqsqlytcaVUlUT5QZmpB3brxwmWwn9O0EZ25VGopriPJwnmEuhF3wFFeb1g
EGpIHeiEpKC4Eg5OcLQ+sRnrscFGmg6jac0NxzS2zWUGmwfdELaRf4TZic15aCHC
8e6t/R9eEgNJINpqYzYyATZwf5VupIeBI3+4AEe4SodYvwmmf1GBu0kDuqiuIbpL
J45Ryttgom+SFLBtPFtXbRm7rlFUs3gmsLa+kakbTC8B18ErJ3W4jsFYCIy17HO3
A4RGt9T0p00jHMdj/Ca0c25tHmks36hFrNMGTvayXjPC7SPFbQ8OLHVY7hRtsRvw
Eyx2EhE6wCm2OtRV1oS5De5wAPKINAvuVE8ATYyijOFEjTRQNdtZXfyqerXAk84C
Gt3qfghV7rxuUOkDBWXfCNTldu9lW+VreSFBDnjFgLhA1va/lMWSKnSveKYaTEMe
1ucnyoYyzxwrm8KJ1jgPUicaCF2MhCXEjhGFcr6al5HUCd3AuldKcX44S0z27Dfc
IpV/rmYLFblpkANoLM0zepqhZNAWtQgBqisH62wFhcc0stmtfEwNaKrucrY+tV+l
kx+V5xy68zY59XDkM/8AUDyQTdkLYGoj6O+I+ruF5oEglGNU5gxY/KYk6UtcLr+3
wnoZLZtDqaVWNBQw/wDhcNK9hGbFqbFwUlABzDX5VQc/dbrOMfCLYAKyroIus8tP
I4+EC+70ENv7kbgemCmX6Tpmu/chc7TO6HUAsA5TQoQSAPCa0cvTnIIpp8eVX0+a
H5XTMLHgh1GkWPRROIAyM5CbjfwsLRardsafuHK1mOvjKy1De4h24dgrA/aLKXY7
cEw2nDKhS0+pcXU0flVtdI44IATMsYKrEXhNb5wbIb5JKubE1qrY1wVoBWi0VgcB
DW4omgFWCgE1jcCG0uOEXIVbionoHO5vsqi8kAgqZLPuli/aWk/so0J0m5xYEpqn
VkEkeyJ0u0k4GM2hhYdTM1tehuSUF/0+IiMOdyU64YKljQBSh/CyMP668N0wb3c5
edetf67Ju1TYx/0x/lZLgu/M/HHv0HPKBwCspCQtMNYlQVxFY4Q5tcXcvqGEBxb3
CpjlLSCL3VSPU6g/ZHx3KFjN7Q5pFf4K3GLdWiWVziQ6zWQUw3VHp7SCL/Y/KUjy
7aCR7LRgY0sdv+0AqKrjd1WbQASDaCYU6vIwjhawnc0G+FZK07TQFe6ilo3CMNc3
7m5yVr6TUNfHuBvz5WG5tn8qIdQ/TyCgdhOVTXqWP/uBTMUg/KxodW0MIJz2Kchn
Y420+kee6zWmnyoIzhUxyXWcBXNfuFKCxjsZ/ClziKQtoqeShjhngIkTaUE5pVEF
1DCqL7se66UmjQS++3uvlRqDe8XYSUzwTu4pXOcMhJSuAvygj75NrsuK1NLD0o6H
JSejhO8ucOAFqRihlQSAq5nBrXOPAFlXFZX13UdDROYD6pDtHsO6siPNTy9eeSX/
AFG0u5GcYHZCeF2njhf2q0JtGeUDrVRt6iPY8+6T1MhazaPudwm9RKXuvssyV/Ul
JBwMBc5NrrbkVSABoUQvMZscFS/7aUMFsXTHOUx1ADuAB+VY2aRzS0GhVY7JEnNF
XMl2t2g4tYsblaGmBFAWSmnOaGEuyfCzotS5jTZsEcAKQ6WX+0hoyTXCirsF27B8
4Ss4O7a6qP8ACacRHHtsEnKUlcXHceSB+ySJai3w+prg5o/dN6HVh8gDiRZSBbeN
37oQ4xvD2cjwrhOnqdLqWE4OE7vF/wDheZ0WpB3O3eq8A+Ftaebe1t8eb4WLHSXW
kx5BAVoJItJxSNvB+Uy0iiAVCrQVzigEmFBeA0+yo55x4pKPNuJODwrXvFHwEnJL
RGeSoQE8tBzQcoNPCZpLddNPPlcyB2omc4G2+aWnDEI2U0IoomBqvAwhYFYAhqKX
lPr2oE/1AsBtkQr8916fVzjTaWSZxra3+V4cuLnOe425xJK3zHPqoPKAojaFy6OW
qzi0Jyidwq7QMza0vO2MUPJ5VYCpjbbrKuUkxbbUP+1Cz7VMn2oWfaqyLaHDKDZX
urBwuKLBRah0QoNacq52re9tHF5KVr8IgMqY19JfI5w3A/JK5kmMi/8AsuPgKKzS
uIm6F8ErguK48YQQ0mJxe0BOaPVuI++j3CUv01Srhk6MwfVjuPIUsanWPSQakhrT
knyn26kGMZ+VjlgaBJG8hh7XhMMglcNzHgDwuWY6tI6kbA8kX4VT9WKLmms8quPR
WPUScUrG/ThsyLH+EMB+p6jgGbnfAUxaSV7t0lAdgnYtKxgArHZMtjFYUPFUce1o
GMK2kVAcBcmGuajUNCGWVsMT5HmmtFlWJWD/AMS6z7NK0/7n/wDYLBvKPVTu1Gof
K/l5tB24XWfjlboTyuOcqSDWEN0FplXIqzyrXqo8qIJgpqNQVw5QDIcIGnFV3RO5
Qt+5Bb2Ufhda5VXcohSgKUEuwhF1flceaXF1cqDlJ55Q7j2Clji5tnyVRDigfxbV
L8HKhpxSDS+mTW3oPyD9v/ha2ikFll5C81G57BuYfU02FtxSh7GTs4IyufUdea9B
HRAKuACztJqNwAK0GPBWMdBiqwpGAhLvC7lEESuCgKbQEsf/AIl1PT0jYWnMhz8B
bAK8j9f1PX17mj7YxtC1zP1jq4zbzlTd8oRyiXVzQoJsIjyhcEAOFqo8qwk1lA7l
Ef/ZiQJWBBMBCABAAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4ACGQEWIQRrYezX
YIh0jHBZDVXpCkATNsiqqQUCYti9zQUJGrUMwgAKCRDpCkATNsiqqR45D/9b7GbD
hpie+oT8pTrjOFuG+TZUrQspaj+Wz6KoR4IgRvFc3qiV7DuBcb7qzlZXnmJx96f1
INR9HZmwFX4krYuLqFaN9qmh+OUNMP1rzxw1ZvdxXWRo7qx28BgsVvAI6IyuYwuR
vZWtKbnHYBQ+ld5t90w1qE43UZCnTO8P6lpx7oBYWGAsKyGQ6cU3zMZ0tgfeNyCY
CHcBhh6C7jpA8XY9XgevwKXGAUOe0VM5wLxOgCRjkfIXO0Wc4NJKgKM+mc6Jdwgh
u1fwUY/I/CvL1ypQMbHZ7JijnP38OuZiVJpwjxG0bgRYrDCO/Jrs7f+Lg/Rd9BQT
53R6Vu5v1Q1ISNI3eca7l5ITf09LNveyZOk37ypWlQWhr74hOBdc/uyCdqsxcIMx
4VE+Iv1lxf3xpUxVaPVu6iyx1bn04tXYb0wd8+rHJDvaXSpFmWJy7ZvHts69xlRJ
LSS4pPSqsdp/3oRuqp+8m8qMEbl7vqR/BSskaVW7Z8cviojuavXvWuHZhissMdGa
96fULCyzMV1vA8yMJTLgFiVKGV5JZ0lBk0a79deD+eD3XdHnzAY41wFfkyrl+Jam
z4QJj/aBmUuYb7dAszC0cgAwJfgbUEnPTtzfo18xgXrVcgfgf2h5HOXNbl/+nHC8
GgE1R4gVGYHlrngsTh2CG9SHzY31BXNlXtSGp4kCVgQTAQgAQAIbAwYLCQgHAwIE
FQIIAwQWAgMBAh4BAheAAhkBFiEEa2Hs12CIdIxwWQ1V6QpAEzbIqqkFAmD3LJoF
CRjTe4QACgkQ6QpAEzbIqqlxqw//U1TCO9de3+8Ts5Bs3+7oFlXEwVhjH8/H7MDW
sdlkRMfCgVMCKxjIGfAa+OB5FWwaI+aIYCn24rqosdUrJPbr6JC94SNhBw7xxkkR
vlH/xyPwps2z9qVgvQbQui0NPR+PTlkpaS5TGjDSbNMj9qz/e6ywcABBujzYpKK1
f6T2Z5dOzOzRRu86TLTpe0e7C60Fg/vs+iyjIU63etm3cWWMzpkJlxkmiDzS5QJc
nl2CcjfrVh1MdylKR2ZvBKZJPLshjf3W/xaCcl240yPpQ4oXNg5csLOCE7C3j1cu
tYaa/67ENjh+DaewJSMSDdXCt0I+O9PpcVgcfqSAfD8bV35+kbQVvq9SPGQt/e4T
VinpcF04zwO46/XJdyEe9ovpxnsS5AZCmlb+0yd2XLIeFt8lJ/cXdK3LFSkRwXwP
YCtC4CeQ/ClJD0pVbrFNWDe1KhftByjyweuENgb5SrX8HpBAW+sJlBVRneXLgv7C
tD0pLm9HnPAg5nmjIN3y5dLOyxbEla6BW+pXA2co3Y75V4NgT2StfSdkFEebXbdb
vTcFeqAKlYZdrUuW+gRnJLOoTyd4hG1BdkFMlPa20LPokZjizXNdEXsils1A1sy7
SLBAXmmjKoFPa/zfGptgD91wFdN476wVqQ55j/WhfnlHaeuzDABoFMgm9Icc5tZ6
oSRVZPKJAlYEEwEIAEACGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAIZARYhBGth
7NdgiHSMcFkNVekKQBM2yKqpBQJdJfrEBQkW4306AAoJEOkKQBM2yKqpY2sP/2uS
gaESiesLhVN1f+cwK7qmLu3YBk8x4gNvUlCQIXep/+tZeo+juERzcpkQMfyCdK6+
H/b37qlb3RWMDYusmUw/vt1pjMDg2gC+DH3gedQVrRlNMOEn1OKJH+C1AhEjsyE7
gy5rX5UtySW3n36nWkujoWAGxs9yvKYK8AYzsO2kor2fpPv87EqzfSc9V/FvQJNV
KN/MEOccGN6NSYSw3AobZwms8yFMUSccIHrOnvqrOGxhpYUJgh1h9vjWEoj4B6zt
OF0XCdi9aF1/G1SsoFWnnrzXwvoB+ljDuEujRVEkAEHSONOwH1nKCevjK3B6Qzz0
2JdhK/Gmigz94v7xrwEnSUxMbjliJ1LO08+LvRZ7tpiWJkZ6r5BfRBEmBbfeYwPS
mRDqLlEG1NCvp+qVdD3ZrsprU/cfV2FXIvox+MZj9ppYJzfecdpOcZOkOE/C+YhD
lLSec5+2ZfYG5t4VglncL6afnWX11jnRUWZd2cHCVDc/iqRCbITDQ2tlDbNnUXT2
bHfEfpHRJg9KdsFnFjMsTXPfqrrk6FkHgk+fqyz4ll7dFrtcxyHM6cM01S0ZPmr6
UrCBuxAIhNogWuaTGJnQWpuc+dnOBk2ACohG8x5fL99IzYIRa4KDkMROzO7P1q9p
3+uC8g1bjICkzfQrlMpwRBXrrBOGyFYaTNmZFWmciQJWBBMBCABAAhsDBgsJCAcD
AgQVAggDBBYCAwECHgECF4ACGQEWIQRrYezXYIh0jHBZDVXpCkATNsiqqQUCWzui
7wUJExfx5AAKCRDpCkATNsiqqWcQD/4tyzkXdOqP3a12QPku5cL2u1ugzQsyabG3
6L7r/VKLnqy6s4CbCBaoxEi8j/dJDl3gfRQj3M/liM25pXlDhMdQAWVLDR5nZQ1X
Vz8+djK32V1wK0uxa3wKfV3uUglleINp3+LFSFrRTjMGErRxzEWNu8FMJwqnWOmj
gOtckYycQxye0Xop0x+oxQx3V68bKQ3ZwDDNHjUIaNnRHxsR5nBRz5P2z86+mACF
kocathc5m7sMwLoO/bBiKd7MTyA17XuYIA0dEvBfDU5XYT0uzDDMZTFfNvtp3SXn
xBQ+i3DFYLMH0oUXTpQhfdqFP0CuK4n6mwxU+yOQuT5WF4HNmZk/PnEPw1AguRR2
tQg+RvOdImaxu6P/3QTf/ldOVsK6wGHXINtSyjqNLJk0PGLjQyOK4pAuZnav0VR1
1uoF7oOv6D+dvnCJdn5tzR5kmeWp5BtQHIGpTk8teBEdKtcaGDn7yRTHOn9N80JO
uxfFapvqDIHvstjAJ4H4auSUyRYBse75EGRUT40tcSRitZ37OYfWn/qJDwb601UA
ey3bXJbT/Nq1QS2G7nJ2flARDwyDr4fNyUq1HN0tx73Ggb1txnLbskc1rxFg3uom
i0nfpiJOPJDkN5mYQ95EUaHE+MzoENzy62JdRV3Cq9xHEsLrxxtOqYqT+vjK8DIb
X6m7KPb98YkCVgQTAQgAQAIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheABQkRNnty
FiEEa2Hs12CIdIxwWQ1V6QpAEzbIqqkFAllaLjcCGQEACgkQ6QpAEzbIqqkcXA/+
IX1d/v8gfs2PzXJyTv6/wfB0f8185QwRN8kjJtoZXDU2cbE4Id3pQ2yM5n4ubuxh
vQsAvWi8H7lighSPV1y/mAQLUL62WZ8BvUYjEQaDK5NP+0hYtuwRNshUP0fEe/pH
Aj9DYJZxwNf8wxTf0W5s+SQ/0pX1ezV2FyOV5Zzkti8BfH9kDgYx1mLCKSHtkdP5
nnG6J1H5XbzrB4zYHw8KMpz80l8ow9TvwjjszXYwNF6c+wZzaSAHzkJFUqtO123T
J2Vico69YnhjQbPcPYvmCRjn9acgPbpac4TlOTIQwOovXWHDvNO969G7v2C7znBq
k2srbgOt3sWL4Ss+N+9iakpwNW6NnN2sKtDuGCaAhHanSDJH4wGfEUdc9I/kuJdz
VsgyeubSasEEho8XxiVi3rR6D/m1aGI1vCgAL5G033wphviP5IbsT4ztWOdUR7aL
p1T4jyKdu6vc8ZkC8ejTSqOUN4UqF45oFavn3nuiHo7hmswZuxCfDlwCzcTSxcMk
deo3NvRnCHWeopZl4QG4eJhj0yDA+hf4WDt/1bas1BvXeKH6A118/0qzBHthoBca
r0rn20FM82+BpQwipP+bUB7AkD/XwFtYkd0D43iBfcxRrnVWlnSsoL6RHqDxH+zA
8Gp/aQL0v+FKXY5VxGCGYhBlsGKJfCebyX0+uxS5FzSJAjwEEwEIACYCGwMGCwkI
BwMCBBUCCAMEFgIDAQIeAQIXgAUCVj/FJQUJD/1HpgAKCRDpCkATNsiqqVmBD/4w
Zy+DOG7v+Wwspd4Up1K+9nt5yFEPnuHNRH2qrv2RVQpFtIFf0tTaBEuvzxnxGFVA
jfIyulY/MEICoLd4SbARxPuP7ft1Y+JZOHnwDb41dYWS/EZsi18QyOasa5kUYLDK
Yh1HR/glNrxN2QVBeMs3nBQ+6n/lcfW0vjBqNrYPI0M81sFSh8qsWTE2vGkraJ1x
VLQhRTcda7Ym4iiu1+QumNLQN/JjtUMbIEZr+Y+CIp7Sdk9mRFCu3K/wHYDtPVlN
KAR+bDtncdd9cDzyvlEy3w68MqC2mc1rVG5fdw0TGC5/QrCkddM7Fr6aWPY34a9b
L07Dbd/r2byPjPnIxRQ2fymRnGAEHHq6HPHSzdDxOpgBgY5YafgZHESanzLL7F9+
bipz67YIbc/O11Xcz1QZXkSVPuCN4kObj+LUCGs0KAIck38fO/e8BwmMw5qvbuP9
UW1NXUEJfXXd8zRTWR1lcHqJ4TJLxbP9gjh2+dKVzb0aVDzn1q/vijCd+MUzqDdu
6+GaQYE92/Td3jag1EzDulF6xVIPBC0DJ7/STx1nXwkV8R5rN0+GvLWoKYzejM6n
NKwcqtnL2u/ZXXhdiGKlPjHGZwY/q3+jdPxBhYQjukGgixmIkEWyhei4Z5uHle7C
n+vE7WEYExrmbmIELzi0pwUUWwli43XBO86QOXPYH4kCNgQTAQgAIAUCSgZjjwIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEOkKQBM2yKqpGwoP/1hXcFYHwecO
SsnqN7knakBVZMFzmPB6yYy/ZB6usUYwHnBDyvIuVyvrNUpJm6/Pk0YQziZGZ26b
qq/9bbLSB1spe3F1hRaQaU8EtBOesP0jR6nPyGur/Su10eqtmUQWs4nKD3E2HiQV
9Z4xuJVu2Pg1Xh7Yw08CUjZ7KcJvmeJgyxHBnyerh9I+4IglO1JJAd4JgEHOl++H
9bzxpPLsNwUbinwAoFq/W8JmqpB/6X/hVUWuj3kdC0pD/ASYTmULagqHtq/I2WPV
6OEpQElPJzvoMcXN0lRwD8izzcZPDIGcwAIqCHJQdKBmtpGuSQAcWaF+xkaTi3DY
i7d3oKHmgyMGd9nn09TdhkpEesVQfKYwlXSto4z4gzrfamjmv1OcA2nLL0ZSE3T7
vS8kAJOuE5Zvm7BQEKSAJaQU+vWFSN2yAZVCH/viPPUTdR1iM2tX7V3aEcppOKHg
0/56vJn9hldYKv6Y1LE8fnGuOONR8zLasibRCjtZWtTful7LHqtM5deisGvzD3fY
q/j/D+IuVljb+aSLWwMkAPwjUp4Yz02bXoxwmvro2UGlZ8mfyZHeh8og4/vjoCpe
Ip1u1YZxK8pzCBPI6U6uhorIXY8YQSFWhCk/yzrmsCyZJ2ep9V6LYibt6328CtHb
AXMVw4b9u1TLobg1q6PPRzcujlTAR9UjuQINBFbBIKYBEAC91ISzAo7Oo0UJ8aAt
R2gv36xXdXrC9kDyX/A5YUf6bSUmiP+TZdKAFMRXzVgv1MFhmDEPYdYP8Rw8AFo8
BoLilxoEL6opVQb4DYfSHAETpUE0maKfTLnBHTVIESRF17GPuLC444blwNGsFoOX
1XoAy5YA6YYkfkV/6I2KH6eISczn0JJB6NePWwxIN7cHM/Vmd4OyLjG6s4XP8rgv
xQroLVIjSOEUCdntwmn58Uiz109XxAiNZCM1yiqc6b7pBXRcCRvPSCpledee++Ss
z+pRHBVqxBZ/wK1LHla0ZyNUZKUoT5QWJOV+Wk4BkbY+GTrIZbk3lq8x1VOFy4FZ
MNgOtN2vTgbYLYwKmCCk+n0pHrOwkdSaFlv3vsGccFDWUJu9kXlo1gR2lvoIoYr/
uiJzXwWO2D7GfgfGLxzLYKwZI1YprqVHYQMRpFp8jXiFE8pbQLhqIokiq8isWWg+
Kx3oVCzVAldzMbyUreP+Bl9252lg95DHrvDm1B79se+lvEAdpKGZH5zo/1JBVG9g
OdFTJnWqbTa61gTTHy2R7dTrh+Oa64pnuo7IMbArpBp9Vc1UH5woEB0JH8OuogWX
eT4rT53KJrVl7hWinlcI4EYmX8M46mZQE6DxwKpGiTnfSxxgA3WtwHiT0hDs+Vxq
flvAinTGvdq+Qniy2haL0Xb37QARAQABiQRbBBgBCAAmAhsCFiEEa2Hs12CIdIxw
WQ1V6QpAEzbIqqkFAmLYvZoFCQ340FgCKcFdIAQZAQgABgUCVsEgpgAKCRCOR6Hs
NaFVHVerD/94EflKRZhgHpvSykohB6l6eVRto/N/btO5VlhIfaLcaDbkownrZ7ui
7MSK1EyPYwtnAXmjZ+CGxIIy2TInqu7MbGi+attXyFduUKtdZ0H1pEjxsDpv4BLq
pJUq+WqWT4n+v1Yhj/vH2X0RUYLQRcgx/ZoNdFRMEOV+HlQL6cnQdR/n+yyflic/
JblfQehbeMt4Zn7jWRUd0u9E08N8LoRUCx11BGrGIXBlsN83PKgMZMQYbQXT0iYq
YceT2crWtvYs+IzvyqgOZ9l6asLQsh8PX321Bpy7XcZx1mPVAJAytwCCk1JIC4v2
MNCZ+AgwiLDG6pkWHJNzHEFYHBO4CdBvqLBMseWVwEUbk3TaRKPzmCpJ7iIJyhyH
cttmluWRcDHP/WPN1nSXsaxrg9frH0iXErWBBUflF7MARroR8YGWYqsmFlzRvbGw
4/aFkMYQa9ZQEidOrzd7IFrJqz+AiScM/3bkxPdIyTjsGZucFTpdEJicUoGJztqF
JV1QMB7Bm3wmEmPgtxGGT+RlNmL3VnhgFyvWFgw7zA8Y4Vlsyb9eisW2xepVm/aT
LlYyGZoKmBODz3UvPjkZO0YGWgaIRypIs3gVIWSlEFSZxbpsWSlTTo3JBhollVFp
VEjutnFKqG4RBZS2kAwQNfM4uaho6eFQuFxX5VPdGh/icck4Ja26rgkQ6QpAEzbI
qqkzXw//cpobItzNQe4S4spXnJs53Par8jleVh537PiFx+K9hjjWdi+bN/bJUZd9
AjdxInnOX8DCTYVdSggLG/sSNxIyP44dXVJX7Wli+7Lu5eZhAI8ng3/DeUasrP60
1+UDd8Bnax+Jv1RGauDLAuRSBVCPlrTgKuKUvIh5saIGiB14vM0zAI9HAwfsv/Gb
+cXOXuh1pxlcsX7wbgm7oXIKgjgjpmk8RNJrt3mscjRdIKmokBi3dlTNmzrH5WDS
DJDavfKwyrofzKDQ3SPFpkVG4P0gal85+QAiG1R6ufTH9MyNlGPFR4BOKbELgDdT
lWVjfKPfISPAOQzquktYEbyunlM2wO1tkiecaOVRLLja2LqFGCNhxl8rYuJl0OIx
EIDG8yV7HqFt6DuWed0CSM73KF8t9tjPt4v9Om0Vb0j475fOZ/XexeukvfMjL9so
tS2ANWNpJprenDAh2QElbywetKNcD8BoDZlSOtBsQvfMe8IZ6w8pPgzpWm7uCMUr
6AC5nc6iQmjCAMNe6NnR+gxmsBQpc6c+Z4I+fGpoRi5Vk6UTDZP7mtsTTYn37dmu
P4N5bwP7QWD7Db4uv1tqkIFTBC8r+COFvk6Ql0gE9lYHh+AK+paemZP8IeygFobE
aIZk6Kg4RvORomqGSSnIb1lHlT6n6CdgTPOws7LN7JIwqjZ+YH+5Ag0EVM3g+wEQ
AMPLqtsM6sXC+Yuif+ZzxFN7vagtGs8nN4RYLegX2q/VSmzNXX17EP33xDw0Fmnu
hK57Agf4VnhzJmg4KnToM4UOOGUe+siPVQU3tCIQTFqTFJBQFvLN88w+tB7gK3dZ
Ug3uKCTsf4nmtP946DfCWgsdSH8dRSKxhv/HaKkSgCqCrqfdt8pHzfYw3rc7HTEm
PaNzEUS99b53rma609pPFlGRfApSepkDXh9p1XHRrTzsYm+gnPY5QUKI2QtSvkiF
LYzPrYxqRSz//P6KGTxRygJQpYzM3i3FMsUlNSoEDjf+01IjSCSn3+AAIulQYBDn
cS0VeHjvlXqHdeg2RULP6WwopL/KYrtDAhgkwOgLLAGl135g+GhMcJQCxq2AGf/4
DMrxCe7XDlOzbZpBf+4h0qgHlxg634nQ4xJa/86Fhjvg/iSiWJqxDEW1m+ImAqDc
jBJN6f9cE7AEPlIaIbcR9ylW2Pk7cGDqo6+ZfQvm4tD8aCD34L3TexEKfVGOVRmj
9soZW3/7PxjleYQ2UdYXh5CANqcvsPPraG8lsg9xJh0I+hmPrq3zU4/vbUsPhPmk
X+uv6GK9ksA4FFsNQwHBFfD5eN3UsFA+xwEm/t5bk28jbeHWYiuC5n6p+61FCdPx
mEU4jTq8HLq6qDLqpBnbvbAqsDbs4OTa0o8MonKlmb0vABEBAAGJAjwEGAEIACYC
GyAWIQRrYezXYIh0jHBZDVXpCkATNsiqqQUCYti9igUJD+wQAwAKCRDpCkATNsiq
qb5qD/9Jbu36I77DNh3yd/DpaZw5vMzLp7dKppOWPFz6ziPPT7vbE2vWTpuem1ru
auRfDW4wyBX7Sb0WLXzNJSxCKKPaktJyC0LnpHh2lqvRpOshIAWA9PHrNW/KzkuI
eq4JFbVClKP/WoD1FQqlkHWILDfQngUz0GKm7q0fDI58aCOC0Ny7Upx3m+jQSjKs
Gm219UhhFcEgsWw7eWlxIU/2OqRUD7zTGL709ZhyQOIIsC6rPD0Y77HCEYjBOBpE
K8FcAY4icFMwc466cJb7toOqOG7ehKIUcyUYs7zSD2IUpN+n3s9w7lS0xCvfF+LW
u0ic3hBXZbcalk6qNhFT+KG/etoT3j6wFCUgjlj4w7uBTcH60xcFDCt0z78e90B6
UgIHhp1A0B4qSrMUhjO0XpjEXvqZazS9igBu97sLi3LubuuhBV0q9X6lOXtNMBwa
B+LGPIj6j/jmSs9HDKFGEkRtjWw7jwGuWnIkLGbY8WprPw1rCo926A7KK8mOV/FH
cE0bi4JvqctxDiARHvB8PAFM0UaFienjrSeXEeb4DvhcSk4IxDwQ1qVejs0PMiSD
9cXAKCufGzGCryrJh90TvRpMAroPx3tY+nmJf4ULXH9tytP3/kIe1ENzOfkUaDNJ
CICz/DlxnSiRsKVY0mXYRVXtGkDfJucmREQ1S1rDGI2kcx6raLkCDQRKBOTuARAA
wSMu/kQ5mGjWFpP3K+G5aapsdXLVLIZyJ+B3Sw6uLmK509feHYJ2fIhdjx772ZbL
u7T6de+xVtWyBMcBehXL06YsiHJoc8Rl97f403fT95BGmPVqTviEZF66DmHMmTxJ
kzjp8BrE9shjb6bRlszlSz38sMkkvrnHSvAZewtVw8L24B/DVe7UCSismjc2LckN
HQ1CEFL3yPHQkrzuSMtdV7qoCQgspAN7eqQ8WmTyZy5uW04c5XFoz9TC2fw80aUQ
EZR+6sxKs8ZEquqMYZ+kMdpoBs7OA4cDckvOimAPtQGmyYN4HPAvY7lXcfTRGBlM
IgApT2zUI2Mql5PQn4UtBj83KYzdsesH3pmm517bSrdApPhP4CQF/B8K2JPBeCmt
ihvXMho54ibBfHYBLVjxa4Fvw1CveD+UfqBaiqhbiN5GqGVTdmZ5bMSjVI1fFl29
ZImd6rtQaJQJUfBmwTGHLuw/3BoucSyJWZmwGA/KN1LTryMpZ1sXmOgHyvF/YI3x
lIeSXex+g4LaTA+8hMwwHC4KlwcHrZGHZbFvovr6UgjcTNFIHBaYM+xJOUWvNRGg
LAn4mmsIZI7ZdbOl7O3raFae7TSj5kmJR4d+oRVJ2Bg0ubxl7j/zaWhvIuZvnj25
Dbb3PeKJvFQmB4TXyE1gU+Ol7PwHG+HOkJH0vwsq6YsAEQEAAYkCPAQYAQgAJgIb
DBYhBGth7NdgiHSMcFkNVekKQBM2yKqpBQJi2L1+BQkatQwQAAoJEOkKQBM2yKqp
+6QP/AhUdjnyQHGZoCl5nF6jcKUt5dCgzQN6xL7YKpn4afZOhoOm55EN+YD5qHBk
ERhfEoOnUPj2W0pwCcPe9oGltTBxFY2521ccH3PVixpCkFlu4zOy9aUAKvXayVnO
WdJYqJCs7uUpoxIfRxBGwZmSUO0vjUrOoXA3zGU/pbMhGZe5oaJRQNWyQw2rFFbL
2Ec7uJJru5r3zKZxTNuFrPMQmz+j5cq29KaNnssO3qNW3khxT7jZx3ybIE3UUW/D
TsQW5imyaZ0X86yd1LGt54WXG+/GcNOak6Z3cgocSb1nWkS3DaNXI8/rm8Bo6TtI
6fYOYKN8Sutl2OzWLddClT4LG8Ky1hYXT86JGsc79lK9gfAfljr3GryOoxX2zVGP
EhQqgMtkC408I6HBw2z8UXuWjaJSL678ZC549rw6bO9W2ndbD8Dz0m2KFBI1q3TM
c6raxOQRy4baiburwz9m9qlNLViDY8zzKAtO7luxX8tkOlTXTcLKuZgww+pCzVN1
rE0NMwXrbN7GH1DxsJMY1K+vNhXl3rkFZLo73gAP/UOyzCQiWY7H9RgFzBo1ikBT
6k9fSIUamPLJNh8RNRCP1XIpsuLw79CmnOA3i9EHE8t6WuS3vr8/V3YsXZ7y9Iia
mQeu5gsxjNoXY1Dy7SKP0k8zT1TfW8Hf7PWbqR45H+CgnGtuuQENBFUKi8sBCAC/
QcpHsPzj70slgn2RIRV45FncrcxjAsoUprtYon+odAAcZNI9/g7yLtDyW/P3Lm3R
42R841ZrbLTu7EySCPYdeeQPVihFpj9s9Xj/nxJg014cNpJjKIB2hxsIIbXxo5eJ
bTIOSUO3vAhOqWI3Cv2C+DEYfciMQVKbXuHXR0+S8R+Ug7V3A4JsILn7U90/A7V6
gwt8xVht2tijMe0gv5wlwTKXbz2RaCqyl83c/OeCo88YsWkvV0hMFhQaTW0D6U1H
OchyJcKqEeMBWqHQ7C3GQygdbfGhiLaNBNiRFUJQPWrtVySxu7DwBM87lEZsf68N
IfWXusNL6WlF0IHSNQrDABEBAAGJAoAEKAEIAGoWIQRrYezXYIh0jHBZDVXpCkAT
NsiqqQUCXSX8EEwdA0kgbm8gbG9uZ2VyIHVzZSBteSAyMDQ4IHN1YmtleXMgYW5k
IHdpc2ggbXkgNDA5NiBzdWJrZXlzIHRvIGJlIHRoZSBkZWZhdWx0AAoJEOkKQBM2
yKqp9SAQAJgJbT6YgDQ3Vx9PXIPYLLpTqZG1lKFuCJcB9LGgNfII4VlWmLH1w4Tb
DAuGnGtTIf2E9927BYAn9DMwKvtcFGlI2ZEx5tRCtl/jGpkW9QZa48VVUcLyWtWy
YAKF58hnC1B+diV58NaoD8qn4lBM/0LDg502+Ig1PKNiya8rtXlLUhx/LoDQhN37
MWrl5gsBcfdWoUwDADAKyMMBkDyRtdP7oaZ8ppU4OEbloanlmYw/9+voURJFwBS4
xvxhi6/zhRWO84dwbJ4aWkCtSCLcYSJJpnhnN+hFFIixOELDFM+V+JrPxG8ICF5r
SrGK0gE797uR3pFCFxiT9c3m1jnYobCg4ARuLipAPoXw1AJZ2hbc25vKVd+ao2Dp
bW+NIjhWqzas+YtgQGLjcuw3s03awie/7o87H/c5HR1eTEV2UEWiErmmi/iHTEqT
KhkWKa0TlCAvVA7L8HZrzJQ5LxYfxThvjwq5tYzcZqTeNfqLJ3YInIB0NU4tQmKY
HSEnq4M/nKyY+jEGpNNvTGfesKmNwrQk+h1s0TfuWex/ioJOYtUF4uI/Lr2Tga95
3X6CQr7ayGxmAYcULgQLz65TyiqCPHh34kdfGat2wwt7qx5aWFGR8ZqPWLs9dTaN
/K06Z3B5tGzRZX6svoeWWC7qyG5wyRrF58H0bZ6oSKjEi02cBrqfuQENBFUKjCgB
CADE9xujJH4tsvuvwzzkXJowmwe55VMK/vuqLHjC7e6qd293rbLvYpA7WhkL3Vyq
ATUqa+VPZZ9/zInd02WX6FEPgYg65QyOEqzDkTPgzZh4QTzXVPa+K4DX6b3YtpLQ
86ITWs3He9RKK9dDlZwaYOCWh1bKL3pWq7uhXU4AFhXjVb5Gjv2jPaaWujPTrG+z
15fIup+ZFjYJFI/AQLJjxScu7vKyL3Uj9g1ImQ4zh2JJKiAPwKfdQGLW9yXJtugY
2y5uwHVjWnM3xw2NtwW4U+5IgIJEGzzDdImfQkhEZmhssQKpPrD8RIMTYEYXdP41
5eRmPajhjO5JrJ7ahsyKIU/hABEBAAGJAoAEKAEIAGoWIQRrYezXYIh0jHBZDVXp
CkATNsiqqQUCXSX8HEwdA0kgbm8gbG9uZ2VyIHVzZSBteSAyMDQ4IHN1YmtleXMg
YW5kIHdpc2ggbXkgNDA5NiBzdWJrZXlzIHRvIGJlIHRoZSBkZWZhdWx0AAoJEOkK
QBM2yKqp7tcP/3gyen3nwYMoAHRAcb08XZqS6LLUWzKeCtuo+UUQY9A5ihAOXUyN
HjNrTgYBnfv/+BzfdxU7Pe8dwugnv6bA6V7uHAm1u7qEoS3XnuVNg8Hg5XFnGy+4
PaIkBJFA/m0VX9tdXUmbXW4b999whyorwzNL5xSxte0o33l6rbSLdePRpcD5hgB+
M+WCuHyaVPVgyVF26EOKWYd619uaP/ag+HbukyoiS2Twlzf193H+WzoK5hsFzcYl
iXIeumTJ5ESOUe6RzVUWUT8TxwakNEKCbIK2dZ0P1hxGzV9ONWVJ79cVBDlIPV++
N6fkbsChWKkxnTL+1AI12jKPDNOuPmV9N6Svv93vmeqny9CtbqD+jGiJG/Dq/xYc
XJ5H2BG+ZS/G2Tw6e5bjay4ulAdXHSws+dQsqZrztFOIpQTzuyOufm2U8QUuTZAB
jPMVVfuBHeJZ26mfrRTsHi1IXPbgvzLsAMnKIb8229Sp+XZ1eshS5JTxkDxqhArY
0SQgOKXs6q5GUSTEeqw2zdRcUzOA2VMzxsPdFVTqEg0ZNypSeIAaQ2ccISmHZH3R
b8rQkSe7CcLRyNbO3Ehn+fNl7IxkNmzzals/hTAJOgW2PUlJElzpinFUmn/el0/H
wvBG8DKqgXfbFYIrQstgkE6eOv5kSuRUAGNWxm3TZQrYaiEZkD1Nra5suQENBFUK
jJ8BCADaRD22hxOa+6ntwKEPnTZGvA4syMHLnlC38k6Smr/5VTjf+LC+nJbUhk1Q
DLoJIX3IjTICNpFU0JH5S04La446mFZEqGYZdP6u1fiugDc82fRceJsAUdx9QlBn
YE0G9y4mV8E/O+0pHN5vNLG4aJYA07UQZSrI8ap+Hp/YNPTBx0hLFidBnqWKUiEP
wAhjCavX65L5ZZZe4fEvFMOxmvWzQAfF15ResU8+qKFRxrl2UPE9UmKgQwXI/CGO
t8WOku93+vVdep6diSXkJoHM75I1e0AVzG3Tmk45rYa1hRoYYR47991DSbNCxIwc
brSlBbgj0YmjWBMNQcxg/gltxYynABEBAAGJAoAEKAEIAGoWIQRrYezXYIh0jHBZ
DVXpCkATNsiqqQUCXSX8KEwdA0kgbm8gbG9uZ2VyIHVzZSBteSAyMDQ4IHN1Ymtl
eXMgYW5kIHdpc2ggbXkgNDA5NiBzdWJrZXlzIHRvIGJlIHRoZSBkZWZhdWx0AAoJ
EOkKQBM2yKqphIMP/iWPzFzKvKeFnTB9fUT1t3YVCzt5ZV4TUTIP9wc/b5ARtOD1
zpzprhG67DmIGa/aJ+2UevPeZS7vuA+X5BuykeWiYdKco0fzGQwvQsA+4nv7fjoW
xwL3KcoYc3kJtAAYLZvUC8ZK7qhs1i4/9KO32aI7FBlyktI3tU9C/0BbJkKumQyK
L8fSimH56BgKabatofcgF99Id5f75/NA7y97f9yp9PgZ/Efwwnp8jnYdR8JPGrVp
V0XTO9fqHb/RrL3uhZNrkOavI8Wbr7D2RCTZRX39mLvyplr8Mc1ky/4GZ739vPyv
5ja6uwFBz1JupBpdtUpJwo7ieXIqN+4WCasi5joyPOMFXeDArJFc/2j3HLW8iarF
vHWFjQ5gn0a8OeKoYCHc8X/MFqB/4EBGH8c+GFDGcdjmBUx3Lnsnn10+HiZNb7WB
5VjKWjveJ1KL3pNTRc/i2DNDVZzKJ57Jk29yvkWSqwIq+YtQHPBX1TeJQkineX6W
w79iYRgjypsX7iLmTponDaArDHuyIQnS7e/HaFTDmdKn3AyMQbBL7ThswzTFWRFs
L5ZWKTqH7sELahjkDtgqMU7YNIoZNdtghpkxkS+EGmEtHV0rdVs1YUwGBqZgp5CH
gQIjszDNQkRsf56MpIytm7vHaBP7SnB1At/vmpxzMBnH9yx7zQTVXHRrPSPS
=z4xZ
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -0,0 +1,235 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGBiDUIBEACwTbvu3ohQvwrv3eaYKRR7fRUzgFEwbmCXt+e1CgVR9dwAuNp4
1KW0yMg2xD2G6jhoc0z4WaTjt1Mnc8Bk4q+Dt6nFIBOb/DjIeAPcOGP9FKVES7fl
71PFWV4j1eT4e8XeW2TRIdOLKJufwUMGXytQbxGonx/KPLjbVdbYMOOouj9rjbY2
uzXC6JfnYv/9GTLkWiy2lMwgHojknKmL98nhfsvVps0CbMfLE0q9P7Atgxd38XoD
0UbijZsLH+liA9ewOCoknxXuPc6E1TO+KRPVfXogRxh2fWZuV4ZNLe7MN4SXT6Qr
MZAF1ruhM6oGgJIEueOG/5H1wdJ+W5cRJ6vF3eSDXz8ZSmBB4ezixR8wbhj2YEhz
09Vp+QjtwmvJK1INmt97Db1iy+zqCj2s6+Ub/MEzygmFPpcTVnnY4tsPy3kfeL84
V/N0MxbywPZA7u/f7uC8Hs2kz4xaSSbYI3izZuDzklgGOdChUOyRa+g0JXSwA5AP
Uh5gKXDx3hgH33WubkQZdmM8GISEpUaD4IfCe9nw5Pv7cxB/kupnnQOsoDlcmrv7
b3QNxueZ861QRFdISKgxdn2ZqO5d9d70xZHuCfWEnckBXHJrCXSZLK7iH0f+xnTQ
wms9MqetXKTaACTN03P64eXoxgXAi2X/I22S33R9Ftnu6+QEbazLjIj5iwARAQAB
tC1SeWFuIEhleXdvb2QgKFJ5YW5TcXVhcmVkKSA8cnlhbkBoYXNoYmFuZy5zaD6J
AlQEEwEKAD4WIQSIgjp17Kp4aw/zixSOQBR4o/vvcgUCYGINQgIbAwUJA8JnAAUL
CQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCOQBR4o/vvcpTSEACFge0zA8PsW5sy
A62NBoKEq5/NcpFrW5Q7HRwspmLq/HUppJ0FqjmYMaIuDkkiv3+P9Yz8LSml3OZX
Eqiq7/hj7SXiSZ0AVNyluRdGGIO/nX6xVDdS+LTtizBfN2JLwGWCsfVcxpUQl1Wg
QMZusni61/zb6O1VqWB6z+Os4jGLA92HNF5yVH6tR+D1pd0xFxMXczA8xux78E4H
YpjBnf/I8Lud9QS0z6t+KH+wZE5QTinYzADyCFAed9t+38CNJrQgbm64JAE9FoEH
uEvi/wF04SMqEJ+9cmjuEyAVvULUck5SgBMRPx5MyxvBjpZkasNha0OgoBRSEQ5h
tqea7CmKfWaWV79az2E53K8vDtr2NkYe4F3iS7w8hbeItfnrsQYMAGdjjXO9Aqmg
vRWivbtwMpGqU4cx+T+d7kVwKXYMPjcDrQ4G2CaU3SEibFyxPSwc9a+5OEvHP1Rl
7G/XkG2kbA7abgcTOpO1AMpUMvF5MQMr83AzlLDEz0onxQU3RR6UFcOHLd00XX9u
eV4YTbdSQK6Kb58uDVx08hDO8rqyJqXRWRhfA4pqA+2y/hEfbSEOmPV4tcpYoqro
+kAN19oFCOsddq7WfIaqkXyPlZMA0crqC5s53va29ULHmJkMtW7nqCKPp3WucyQT
R6+eF7rw+Zhc+jkX1nNefvUriMSlcokC+wQTAQoA5QIbAwUJA8JnAAULCQgHAgYV
CgkICwIEFgIDAQIeAQIXgBYhBIiCOnXsqnhrD/OLFI5AFHij++9yBQJg2re6RhSA
AAAAABIAK3Byb29mQG1ldGFjb2RlLmJpemh0dHBzOi8vZ2l0bGFiLmNvbS9SeWFu
U3F1YXJlZC9naXRsYWJfcHJvb2ZfFIAAAAAAEgBEcHJvb2ZAbWV0YWNvZGUuYml6
aHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vUnlhblNxdWFyZWQvMWEzNTBjNzE1MWNm
YmJjZDhiOGYxOGZhZWJiNGJkODUACgkQjkAUeKP773IZOBAAm95gnhIty2S1xvG1
MhUWI7yUlCgKYu75SOVYnr5Pzgs3oKCB6lffBTdtslqcsw32FzSSJ6ShVZX5QxVw
spgxv+r46CQK0Dvh59GgvN6DhcLw3qtJJkgE4PS5dN9wn3GIV2uJJOrnnqIRh1Wg
XdmMZfYVlazWqfgfJygZ+WHdk+5g8fTvYda0qsYWZ0pnBcqC/zfEMwNDTN1bQEJ1
YAvatNAw3KpUOHrsY1yBrgAIEyArf8DJ7BzLF2V1n5Ee+YOEP66+9kEn7TDA0lV0
xaNHInE5orNro/BFmwj0faCW9YZlB/xP+Q9Hbl1RGp9YPhVEkFTFASKqMwazMrat
wV7mW6MnaP+oMzcBHhJq5UVXtxSTUcPLav4G7TLkO0iU/ztiPaIw0L5OpEYjW02i
yYYWftauWqbkDtMjFJ9Elnud86/IO0ZTQXELLN+nnZVMU3lqw4VK2gmfytmlk9gM
uE2mvTbnFWkQ80tUaYCy5fIde5Qg4vJxG26Sr0GfJiR0szav/9X9Bovc9I7xkmXW
bGRtfgMFDY0K1GkvN2mk6uikZJu5iqd+x34stvbnAATpMLOhAWjbV4/dJDBRlY1X
jb1ojEdmAmI1FHT4d90y/jc7xNHY/wq4JF8bQjSM3JeWc/RrC8rqElY27ERy27xe
AJiNQyJt2S/hpBYMzJ6KagNodACJArQEEwEKAJ4CGwMFCQPCZwAFCwkIBwIGFQoJ
CAsCBBYCAwECHgECF4AWIQSIgjp17Kp4aw/zixSOQBR4o/vvcgUCYNq1El8UgAAA
AAASAERwcm9vZkBtZXRhY29kZS5iaXpodHRwczovL2dpc3QuZ2l0aHViLmNvbS9S
eWFuU3F1YXJlZC8xYTM1MGM3MTUxY2ZiYmNkOGI4ZjE4ZmFlYmI0YmQ4NQAKCRCO
QBR4o/vvcspWD/9tPmipSq3Bp4V12PzTr1U1FpRG8mWzcqZW2CpNGSIK9AxFH3CN
yBG9/CvCSuDz0Lgyjl69ixoQKGlacfDHRyPghJrRzzV4TTiBpMmRnqgi/TDnEr1S
b/2hFxT3/XFaPfTVIc3JPkfS/ywRf48UOt3gF/A3/CmVDNfQWUpW0+1Z6QcjmTfX
xNhYUF/CqyyapfuBuFX7wKoY1PBZpkOOoycKlEyrtJjjWRMCX5ZD09jhVVI8va1U
Umxshfol3yapxGwkndrX2qnIHJbVwwJrrxr2i3jMnp4+EopK58epSx0d91vqGsti
JJCl6PHB5XJthyyFZj5DssDyFPnf7Y1RovsXcoBU6TLUF6k1jk9V+t6c0D9PQb5v
UJTprIOHkqCzJwGsflyJiLjWijk0kUN5XDsUp+RqeweIr+5o0FI3HLOGE6cavRFU
NzXPHTLBdDFWK8TPH3IJ9WdHkAWkzPDzuYokVR8HCVQygrnzKm+iufr3UpOLvtSK
I0hdbfpeAj2fNKEwPoK/XS/AkjaobMuhwYB1wS/ZiX7lBrWxULYKzdCp1qPTqD5I
Hn2UMw1kmI7jSd8/gtYosHf2cKukc5uFCMUj0lLbHJGpOUCRnpAbarypY0heH3Fk
1nDNWwsKfX+hxHQgSLl/TO/YBXcECYSnWrHlAPZzfTywbeFR5lW7n/QhaokC+wQT
AQoA5QIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgEYUgAAAAAASACtwcm9vZkBt
ZXRhY29kZS5iaXpodHRwczovL2dpdGxhYi5jb20vUnlhblNxdWFyZWQvZ2l0bGFi
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
=y7aU
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -0,0 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: website
resources:
- namespace.yaml
- ingress.yaml
- website.yaml
- wellknown.yaml
configMapGenerator:
- name: openpgp-keys
files:
- keys/88823A75ECAA786B0FF38B148E401478A3FBEF72.asc
- name: wellknown-matrix
files:
- files/matrix/client
- files/matrix/server

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: website

View File

@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: website
spec:
replicas: 2
selector:
matchLabels:
app: website
template:
metadata:
labels:
app: website
spec:
containers:
- name: website
image: codeberg.org/distrust/distrust-co
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: website
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: website

View File

@ -0,0 +1,111 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: wellknown-openpgp
spec:
replicas: 2
selector:
matchLabels:
app: wellknown-openpgp
template:
metadata:
labels:
app: wellknown-openpgp
spec:
initContainers:
- name: generate-wot-data
image: registry.gitlab.com/sequoia-pgp/sequoia
# TODO: distrust.co is hardcoded
command: ["sh"]
args:
- -c
- >-
cat /keys/* |
sq wkd generate -d /output distrust.co
volumeMounts:
- name: data
mountPath: /output
- name: keys
mountPath: /keys
containers:
- name: wellknown-openpgp
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
emptyDir: {}
- name: keys
configMap:
name: openpgp-keys
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wellknown-matrix
spec:
replicas: 2
selector:
matchLabels:
app: wellknown-matrix
template:
metadata:
labels:
app: wellknown-matrix
spec:
initContainers:
- name: copy-files
image: nginx
command: ["sh"]
args:
- -c
- |-
mkdir -p /output/.well-known/matrix
cp /input/client /output/.well-known/matrix
cp /input/server /output/.well-known/matrix
volumeMounts:
- name: data
mountPath: /output
- name: wellknown
mountPath: /input
containers:
- name: wellknown-openpgp
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
emptyDir: {}
- name: wellknown
configMap:
name: wellknown-matrix
---
apiVersion: v1
kind: Service
metadata:
name: wellknown-openpgp
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: wellknown-openpgp
---
apiVersion: v1
kind: Service
metadata:
name: wellknown-matrix
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: wellknown-matrix

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,31 @@
{ {
"data": "ENC[AES256_GCM,data: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,iv:/fRxTZXtnSmxNMteW8+2bIZ5cJmp2porggeRREXwkik=,tag:nfjWWixPzVc19ks3T0DPRw==,type:str]", "data": "ENC[AES256_GCM,data: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,iv:Jh35HfEzpjSOHVATn81jArsnjX1f+CViZZdwngJWp9A=,tag:AuCQNC35S9U3DgyWp1MjfQ==,type:str]",
"sops": { "sops": {
"kms": null, "kms": null,
"gcp_kms": null, "gcp_kms": null,
"azure_kv": null, "azure_kv": null,
"hc_vault": null, "hc_vault": null,
"age": null, "age": null,
"lastmodified": "2023-05-09T11:31:49Z", "lastmodified": "2023-05-17T02:28:37Z",
"mac": "ENC[AES256_GCM,data:oLQeWOAcZkdItVwUTfqEYK+rE0YWkwfN6nT/JXirs+9HmuHmOZV6oVyNNSJisT2yOUv2bua8cgR+houQXi/3eI+ImgXBULc2uA0ZjWcBtPHeVpnXVquCVT41dilQv9mikVD6/P3G8QtJDFCwaQjhfYegJV0LFlIy2eL5XmhcRyI=,iv:Bj5vvuu3N1ip+kANvNbGicVD/UMaTWr2UGTHnGTrNDE=,tag:BuY1dPyw8j4FpqVIl5GWxQ==,type:str]", "mac": "ENC[AES256_GCM,data:aL/a8y2g5+maOSWg3QnhbNQPMlQnoI1fg0PKb4o5F9mUMWJdXHoNkXDUGfI3w8J+zgH8lm2M2hsYuVwcyX5Tyllbq+NHYWvDrK+34oRxAkdP6JDK2ZOgn+SofjKtN2y6EVfnU66I1UnAZcmzfoANFVfy2qvbZdw8j2+K3cxBS/I=,iv:8U4CvwSmR5rN2yE+l+idJ/sjUTNgoTgxut70iJU6mD0=,tag:7N5VK1T1JXJLEkeBS6tgfw==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2023-05-09T11:31:48Z", "created_at": "2023-05-17T02:28:35Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA82rPM2mSf/aARAAN0gGIGkEeD0Gb+NcIA7aEWnlCkBs1jCzuIl/GpJaWr7E\nemJHSKapcy+JI4ebiYESe1IJ33Bd2nldgLckAsC0t9bzzk7NwuDhvOi2n/VOZxxm\nGBampMVHlRATMkdD1X3clrkBdqgsbg9PGLEGHFwZnrW9fJvV3swLR8D7DxMbQwmB\nRAdkted/Q9sBmkxZG664zS0NwWg+3R8uIS8JIjyrmRU2wj5p3Mi/fdizhmlIcAX0\nCmop68Azinodn2N9gTReXuvnwhgmytVVBIv5l4D+8vbzKIF69oRkrZ2GPwQJ1HT9\nw7ZvMCgoB434fAc5IgCslScRyBpUwx3/EKhYXOmtWuQW3oZFJhLuhUz7W8Zu9d3L\n01UmqTH6FGIXiBVdOD3MPT1OyDMI0XQoJiPZdHDTMuYXQDICujJL1FPVlbErdY8F\n1bCZ/tNNSPbyucUF3Z7ujx5LE99ty55waK0QjorsNTx8C3ZaZBQ9BqFIH89YpV23\ny2CBSGK+Z1XQXFda+rrniRtiGpc6bSlyFCEM/aMFHUDR4ZQEWMqHk+3clNmzJFKO\nY2mJszVQY61NVr+Ww2Ue09XCv9ly+73tFGAyLpmloACLY8rLTehnJsuSv4rMHNyS\np8XSuC8TmaDbdwvW1Yv+Nu7JFPV8ZOuwk9Y5gd8A+GV2byMjPwwHvUn+6DUGFxvS\n5gGB+mQOKF8gCjQZGpUpfiTY40XyCIjeZy4UWjX/pKgwfuq/8i3TaojUgvXzzSlp\nK4ye7G2orL8uCIfYx+JRbr/kaVro9GJbVLq/fFzBEIwi4eKJxKjqAA==\n=r5lJ\n-----END PGP MESSAGE-----", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA82rPM2mSf/aAQ/+NN4tLIP2lbgRq5AmiwSzZF3Y8yhZCT4xAW7pW7S01YDx\nd0ykCA+gNDF5oLnXtGUvc0OnpRb7I96/HmeDRs8TfA8WaxqIo5xstpdBKJKbbpy4\n8XlgVUSfDLxOmzkZLuUByLd3IW+IT/hk7zNj9ou/Z60DKS3hASdFPu9hnRAKcnGS\nmsL20hGgmw9JIeV5lpnIfBE7vHnEtTNES5/OHKzhpRS+GxVgCQ1eu2uqe9CI2nEr\nI3iAc26xbhj46Dr+od75ZAcTS+iYE5mTKaUc9410sus2UuuuQYhEBnJflUIReEVH\np2EIg+Cu80FmZk1FQyDUCNfgXr9+7k7PcH5OeFqtNL0Z9IaLFwM+YekO0cOwFzFr\ncW2ipBNitgLfihVoKzc2GVf7W0wMKWSbYrCqGWZFXff8dUfXOCtmkLgpZW/BlasS\njDKZZRFVV9yjQX9DoHamNyq0PLvGuNV5fcJ6j+N8MpOo9E2BW5dc5FwFU7w2RoZ7\nw+dCdru5GTCg6fs+lTQXtniPGwISML285rlESbD01ZiV5baYe26tBh/g2Ejn0fqt\nvPxvWRtm4v6u0jBZKnC3vCoBOFSjrdxyIcUJUvb8o+ITsjoY7OXLgf3fnidHXO74\nb0ijM317Kcg2WyG5uSVdRR5LkQaeQDMH021VrLPSdY0tDnbtdJYEznAlQmHbRw/S\nUQFVS9odWewyEDA/R8lTTn9+GOMpVmER9wFsmILzzmNpDrXkwm7yv2V9E35QdKo7\nY4WFZvxI03cxVxyigkCB8y6Y757j8gPb2ldaGyYf1q+uTA==\n=LY2V\n-----END PGP MESSAGE-----",
"fp": "6B61ECD76088748C70590D55E90A401336C8AAA9" "fp": "6B61ECD76088748C70590D55E90A401336C8AAA9"
}, },
{ {
"created_at": "2023-05-09T11:31:48Z", "created_at": "2023-05-17T02:28:35Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMAw95Vf08z8oUARAAuHfJTvS7uhR2bQca5hBmO+qNoK8XwsPwOXK/zJvAceBh\nvkNgUWVGu4e7bctLkIAexp1rE6ggnVn8C7AmC4ZHrcHAJGTyMJ/Z9CCwf4of9Hrs\nQe08Dc0CzsTAReSbENvHCXho2c77HGZ8HJw1gK973QNcmlp1/PDwHKEbNisvaZjD\nDlb1piIfBZ3R4gozNHY4vl9kP4rOa8lm3VWt9dOn2JqBZKlBbtMljvk30Eyzy73l\nbp++Ayizykr8EJDJUwYsENsoctYppVxYBe/wWY+BheJN3WjtwnO+lItqaHJZp1ve\nXDJZ8QDieR02jJWzCU+axW0zjd/6HVjN3ya0/JmGmiUCrUfJDv9spsao1ZOWtwrr\ns1uYGzR6uv6LwiiS5XKZcbfzAHfYb2OF01Qc9yZJXmIKvuS5g3bRPODz1ujmErvp\n+wJYlfgA+XwSqR7nyefNd5buW/mCXjOR+z4B91wFaKEYc5+pWKdP0iC7XKJpy2X7\nUm1Or2v/OPEPI9BTxI9Yo2KWBsLkGkXETtVleyISfufGR66X0FUYiEyEBDfkp/U2\nSrrzbhmfzM2AytfmXWo9031ettQJ5y6Xj609jYUCa9E3heydbqStydlow4OhztpS\nDNWIAHSiM+aXquHRWuVF/6imeBn6gEbq8iyN2u7A2vsB/2U7psY5G1CyGvOkdKjS\n5gG3w1xUo21uu7tk1sHGpWqw3IXDaLVwin0cERKoNBF2tv0Cgby+5hgqXf8qOZZG\nPIHonxnFNaRjE3tGlZlpy2jkN3Gu4QVLlcv9ZtrvY4LXguIO90s+AA==\n=ZCvU\n-----END PGP MESSAGE-----", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMAw95Vf08z8oUARAAi/bqUUMhs1pupcZnXlzqYHVPedDpX8AjsMstbpnaGppD\nYGP8zl4I52GeHD/ahQO1P/MBN6qLhx8WyB72wJsuXFJuLG5JboseWqLKFrMotUDS\nGs/robsVFiRQ0qJ9xHYDsXC0NxtlqeLYbKr9dhr1c8kJUHKCfqIULlA2KlkCTsUd\nldXDAvOr/gfmxzbXWcpufMtNNgi/Uwm4U/kBPp/e1AmD5TPil3sExIs5RIukg9ab\npDffQ9C/Baku2Kq6JpkiWbvHBMKcrmg709AhQKQ+9hzFP1EcGva5aspjPDjWOzGD\nImvOcWXvtTlVOEKUL8mP5R3k8rX/p9LUMf9Nvwkhx+F406eqlebZxf6OnnIseha+\n4PUbWTlb9jdX0pOzHmc2vQnwAseaEPA54s26cHFSAWePFMGal8P1arrgTQsQhj+Q\n9s3CEYv3qti/d3yFzbHbX9f9l7W5KnNlWN5rGJPnhzaVRRqxbOuPell/i1TGX72s\npB+LYlQS3HLfeZQaUG8GDZBvKkfWrg18Y5xeqcoU+GqzvIsZTwrdB1XTrfOGZ5bO\n0Y9PwUTuOzxtdWIYOymt82eYLhEVd4RtduuCTQc8S4ThqyVgUS6yTfMM/D11uD7x\nDtOJTftlPFVS+iPiBOQrAr2Q0/RG54nwkLKwgGjiBkzqIrRECL0xh5eSG417egPS\nUQG3VfpXqvaS/J6Mc3FinC3PsYeo9haN1keRhndjI1xt9o96t/lXDC9rlD/Nz4qX\nfjhzSsoKGMa1x4kslSZqXNowCUB/ISbcU7y5WlNgYdQ8uw==\n=uV5k\n-----END PGP MESSAGE-----",
"fp": "88823A75ECAA786B0FF38B148E401478A3FBEF72" "fp": "88823A75ECAA786B0FF38B148E401478A3FBEF72"
}, },
{ {
"created_at": "2023-05-09T11:31:48Z", "created_at": "2023-05-17T02:28:35Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhF4Dr/MjkOzuuRESAQdAptywEQLYSPEsVUxfe+If9rhrlxSsoJW9XmPf97OCgRcw\n4K7Yzg/2YdH52MY+z4YzK/sArtUJF/s4UHBZPsW73uPt9WYxRllf4fMxMdDQv8oM\n0l4BKabKtM61S0GFfxWO+DylhijxaK2jJFfrNTjj7sPdiGlgZ5LhSriJKITouYbp\nMzI+0yXyAtz+LmEGKp0w9hod+s7juAHon4SZFGHGPydYZI7vwB+DaWFn7aKoH1LN\n=XI+r\n-----END PGP MESSAGE-----\n", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA0/D4ws+/KPtARAAsqV6EQGRFC20Lo9NhLzh2NEzdXN+m96Tk4F9EOKY8J3Z\nBw66zVLi88XbKYmKanseWEn0Tack9EsrUz9ZTI+u7hNe1kJzopV5ehjHt5raXQvy\nLlDNEombcpLDO2jRZQmSB5nrhrBZFBxZLPKpAY1nixTchTiXVDVa1XwCh5A33u2I\n9dqTY7ZzQHg91IR7eaIIOtAC2E0hpPvDxAZdAe1CFCD8Nj7+t9sq4X14UkMbCLF/\n+WUxspmrW/QC4AeLaWL+DkhT13U+tRzVqI/WvwrvsRb0S8WLW2pfmcAO27ohABcd\navhPGIZB7Lpx5J5pcf6EzM45F99gj93SuleT+u+Ty8AOMYclBIn3CF0w3RknadQf\nmgjrbeSVAIEsDTx0PEbMpxT55JPMLoiuQ3ZYZhcFzPNpmtGDABz+9c/Hso4i6s92\njvmM/6lkgUZelLPcVUi+uhpfVUzp6pl4iRGH99eU3tKA1BJk0M1GAN2l7fQr2j0c\nRvAEsIFgvK7P5FyoyhdgOAMwnVe6Jfdc7BuU7LQ9qHpSjLmQcBLHpWAbOhUfZkfn\nGMTzMZ8BDw7QgTJtcYDtjVFHRrjZ25SNmjKyjwviyzJvXw9YXAGSOqCkD3v+2vKL\neu/ecWakXQ8qP1EPVehIyrrHt6Wr8UHheVmpdOAirOKqP7aNPu/aDvRi0A1LsyXS\nUQGEj0DmQAkBigG5lmLgcn/pOArFiNUx8b9avBcWMUcwVEcMTJDaA6HFW4ZSxsfG\nkBycUaSB7um3B6HrIBD4MMBh7ByooN1/zlg5HeM5OpF19w==\n=YQtU\n-----END PGP MESSAGE-----",
"fp": "3D7C8D39E8C4DF771583D3F0A8A091FD346001CA" "fp": "3D7C8D39E8C4DF771583D3F0A8A091FD346001CA"
} }
], ],
"unencrypted_suffix": "_unencrypted", "unencrypted_suffix": "_unencrypted",
"version": "3.7.2" "version": "3.7.3"
} }
} }

View File

@ -1,31 +1,31 @@
{ {
"data": "ENC[AES256_GCM,data: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,iv:BGH+GrbMUC4lmyM2RDqRT6JiobAQ0bez0srTj40mdXY=,tag:mZvBNz5TSAVLdrkv5Fs2/Q==,type:str]", "data": "ENC[AES256_GCM,data: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,iv:+Ur82pTHNCfCIC1KFnzqckimXA6uli6+L6mdaZWK/qE=,tag:YxJU68hCM4a+yq01wnRCgQ==,type:str]",
"sops": { "sops": {
"kms": null, "kms": null,
"gcp_kms": null, "gcp_kms": null,
"azure_kv": null, "azure_kv": null,
"hc_vault": null, "hc_vault": null,
"age": null, "age": null,
"lastmodified": "2023-05-09T11:31:48Z", "lastmodified": "2023-05-17T02:28:35Z",
"mac": "ENC[AES256_GCM,data:T4PPwLmz0D5BQgxkB9xy/XUW98R0aaZAUOSgo9H3860YfopezmS8VZPh+UihS60M7To/qn3mXBA60wEkFk7cH5KF0zfwBSpJkp9466v6CWNjfMtN9/hToBLHSb6ivpsLmwedkDLylh/qxMKgGe4HsFr0KhSHY3a+N1ljN5+pNiQ=,iv:caYOOnC0j7bJhVCT6te1lLGWz7S8e9MzBKFxBVS8oG0=,tag:DbbRxSm0CdK8ARMGILpv6A==,type:str]", "mac": "ENC[AES256_GCM,data:3yKNE+tLIsHJpnWPj1Wtf9jczDZ86lO4iTyPjcKuBzPfQZVaFTH8Hq2qqbD9ACOGxPsJoow2JdZt71uj3E+UUZo9C9ukHcLkasIQGiduc7vp/UIr/PfEVJBPanQqGKhrS1W1XxI6c2htMaUROexOxMynqzsa1Vl0YHabk4Byqos=,iv:H6gZTkIcuCqVpyGqVhty9CA7ta5ZSGVAKtBXvUhKfRU=,tag:AUuV1BUN1mjVkNKI0HJc7g==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2023-05-09T11:31:46Z", "created_at": "2023-05-17T02:28:34Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA82rPM2mSf/aARAAB82QM3RRrKXI9eDllD2U4xVBaekzjOm6OtMAdz3vPRn8\n6UybEjhx10P5viFfue18BJfLBQS3gPlhDpPJilbKyIkjhoTLqTBWbo9LtULMD7b0\n0IRl03hOjeME0nLMRIGYhQd2bug827YaYrHIXAV6CMCSeF5ZCUmeqFgke0b7WEeQ\nRxphEFUcoCSEoJznKzT2Rb+Rq+aLir3incyV7OIYhkUyuBEJMeiSUT/3PsaYXrEJ\n1z25S5cNTZIyLp5biHoKG3rUm8KKH84oUzMtQI1Io/GGTVFb5foJ4Kvrn4DEJNhl\nnNCU1GJoknY7sP0GXuBsolKxi1DszIGZGZO+r0DWSP4nzgFyRXEQLI1RaWCewEDc\nEqggq88BWPvnJuff9oaol49S8NXfrBNrof+Ed+OIxrZ4pY8dhIwlPEFAN7WHWK4U\nnlVaVKC6ph/TZ4pN/T8MMY8kP3ZIZsy9HVK5/KitMlCK8yut/5dVBKJZwbcT8VyQ\nJJjMe2lg3wKMK3WEVGYkTe+fmmuxgYFAMK7nuuQEBsFnyRkCWUkYurhiw+itR6sy\n6WfvxqWmsIhlW5tA0iCkul68RbbsS5O6kbE3qwUcW06KUgja8FtdmfsQxUxXEaX5\nhSqG56eBYqmroHZd9KoXHeqT1+6FJrOJE8wzKRRb/rp9Sg+nIf9zCeLmbF3DaCPS\n5gGmkaK52OHp98LN0/8f6JxQhC0L7NAmW1S55MbFUrno9EYXBHAwmqyMzgklqG0a\nFVgQVU9CVpKdh1IS48ugyHjkiUr8OcZtI5ntq+ByAJbNOOI4UtW4AA==\n=LmxO\n-----END PGP MESSAGE-----", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA82rPM2mSf/aAQ//RLLRtFStBU4lopeZggmgeH89hHNR3mP4w0Qz/9IbwsGX\niduRIcxIH4T1gfLjGosah1ma97BMOJvVibh1RkgkSJJD172uppChutyv7+8aruo+\ndhlHPzYHlsRM/2W5CvVG89/g2mljo9Ag7s388qOlI6qhJTXh55+eroisX7XB1cQo\nnr99gl6/6rwai4nIU8sgOr/ByEipKTe+4LhAqc9asWcAK8D1VGyvrY8CqpYSOUzC\nQEsERMzbnRFyZSmigNv/SadAuPpCTKdswwOusRUut5aITrfc5QTOHuvkvdm5Jjss\nTvsGzpZtTMuj0I58lcCumLG1AMNlKKUHrVykOL8janlDlXZlh9abo3pZGEnIcAXz\nQHzfC+s0Cg4dvmmr1grK2lZcHeIhIpIcIDXIGoVbGwFzNh+ppoH7JOcKHTeRnFH2\nYNE80lpEslJ7ogiI98mxRkhRKnGAvwxzuw0OMb8kIgi7GBDbPjmvWLyGaoESXhbd\ns83ne+n52+05SLJAGHAConbG8hA4DotvOATP9qK7AmNGSQTBhw5I7/Ku0l667axr\nL5ictOchh1SmQfrnaOnKfNlVkgy0Som3cadDRBHcmZoYhnmwm+nNyJgbR0RIvK9F\ni7fPMUv1D7Ksx+FYZOJFUkBxfP5cQU85Wy2HQmFg1rkLRzuXVlwuM+EbfOU7rh3S\nUQGKthvVRGlJ4ssrqebZ/lYSKtVzvVydpNuCfEDDqa1ROLUYerw7TxvijMpBoH34\nDB1JuHVyCETsNJ+qWpr8BLUAmaoQ9B3XCENSfR2FKZKDUw==\n=QrHX\n-----END PGP MESSAGE-----",
"fp": "6B61ECD76088748C70590D55E90A401336C8AAA9" "fp": "6B61ECD76088748C70590D55E90A401336C8AAA9"
}, },
{ {
"created_at": "2023-05-09T11:31:46Z", "created_at": "2023-05-17T02:28:34Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMAw95Vf08z8oUARAAijm7yxe+p/CnffDusQGA4p/uZtBYCQsAQYW8QYSKG3WE\nKpi+RIHzhFFpMnf/6W1Ll67H3tdbM43sv3eaB7I5FYajc9KPtfU7A49/XeeM1acp\nybvXf2j+vVooNJ7JGSBg3CGUZPjR22dbc4ZxpfWU+ssKs7/Pk/fSpVTsOjjjJlRP\nJrYBHRYlUztuxfmPEJIdWFJoIZ577R6r00KAkB1r7utwT15FGrNdWasSlht5ZV+3\n3ZFl/YDyqoemj28EXX0rBT+j29PCHAmwGGE3LoMSRfCAFhWjknUuiuS5xDUhl//d\nkjGN2HvUFQYpJ592sd/lBDRKKtWkmebCqP/2ZQf1mzhDLOv1+UACtGq7cFA2pvfr\nhzykY7SNdbyyxakP8t5EaliFSBfkRdvqegyW+zHByCxn4SCxfjOdeIiHLEuKlpij\ncswLiMu4WsScsceXcRc4P+NZEBI4i26T1ruWV0MJl+FrC78RTCSj81zUdRsUWL7+\n+hJQ3ciTlsDWIP9tc4fKviUikb8IwDb78Tv4KXKNpghosIYnvScEl195SVWUNLda\nqU9b5CzUXa7Oud9nFYb8sUTWKlkGT/9hhUgI03yvR9mO36x+ELRuMjWwLu34IU0b\nBnA7ANIHkFkzYAjNd/In+fwG38taQwU3VVQTwgExg3A/pYTx1/VO7IWEMZUAkUnS\n5gGb9FBEg7YngpRloF2g0YRZnX6omn9tUA68cbIyQU/xP5WTO5uf8ov0aEEEkOTX\nDCC8oDP/9jLO/hMuqGqRj+vkwKMDLJxKnfJHRX2uqRsnMuKV/1m+AA==\n=/AEZ\n-----END PGP MESSAGE-----", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMAw95Vf08z8oUAQ/+KbyJUpPGx0UhoIFyD2hYZAJsSwX67OwXMm55lSyAIjQ2\nByuXUWRlrmIN4LSiwH6gOHP4elgIoe7XBxKHkZLFgr/RC3ND3L2m3E+M/2p+epUa\nA5khOUZpBueqOOkzv0lYW8q0KZa2qMejCdcgbcLm8svMK8RbiUee+aqwXiSY+RH5\noB+RqvzI4OwTSwCZpbOYxr9CH/LyNfRT7ivQXhigo4v1qzcfKxvdyOnK+1RTo1bK\n9yW0R/sqXvSup5GTfsb8jnvBxLrNbi+S9rr8IzRGla+bDciRHlCWIMhAogtRpJHm\n9Steql7MrnIq6UlOCVHa7rYcTIIu99extBpaz7JUO5xND0KPv/xYovHiMMmTmH/X\njfi61aWNoSsm8+iYwkHPVSRsKccJyb64+h5uFoE07cOx0F0+gIqN9x1Y1JPr6b63\nZpmkp1W5ZkBjX9O8tyu3SDu+Bx1mhzsAvqRzILftzK+yksaVL10309cMpHbQ5opa\nonmttsNqQnGdx8BCB/UdqY8ACOVUmDxm0X/1hG/Rz1gTDOeA2WbcwzVFLj4fadKo\nsynRiWd8AnyyraVKuAAe6VgQOplaZsJsqERK3y8hYEKXwEIj+0G9X85dVNVDcx3L\nrAUcps9lHRS9POicQO58YPwZ47aUjSUSVnA71aRB9MsJ7wGokSV0fdFkWNGCR7TS\nUQFSJP20DveNQMqANyq4wUXhXPqfv1TZlH9Lz/bzzLLvcDTBUg63mJytSzeq4pps\nIddiTi6xRtW4QBe3wd5V+FcJci5D7tZtD0hLmJdiaz9JuA==\n=P5LB\n-----END PGP MESSAGE-----",
"fp": "88823A75ECAA786B0FF38B148E401478A3FBEF72" "fp": "88823A75ECAA786B0FF38B148E401478A3FBEF72"
}, },
{ {
"created_at": "2023-05-09T11:31:46Z", "created_at": "2023-05-17T02:28:34Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhF4Dr/MjkOzuuRESAQdAcyI6DIR119ygGZBc6BogAfW41/azzCdGp6VDDfki8iIw\ngMldmagdRxRWGIulkP3HHU+KD4kQb0wdmW/Cf5D60Y66SC20SC2NqLRkGP+guqfS\n0l4BFwjo/kYoTORGfOkIPTc+qDawUA9XrSPFUfhP2tZ4iX+90MO3GcQ3PYrnUDwY\nWCiQQqUQ9W13wKG9z2iTfMKuK5l9bDt2poNqyAZgknyxF2fltBnSsjgU4SlmdNmi\n=qqvG\n-----END PGP MESSAGE-----\n", "enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA0/D4ws+/KPtAQ//UiVmychH0R6vKlbcPSp5rprJIzC+IP76B6GQSoytBsCQ\nRQI/FZDGkA8dfbACQ9kxNJy3b1L8lhx6wb2xM8voAK/TdktHcE429VpTSpUswrhW\nLvmN0wZrRVnvFT159FCMSQbG+3uyGXom9jOKWuF494eK0cY48jiW/i0HB982grGE\nX7AXJlSJIKSG7VixoAaIX/rZOS/aIcks+LeqTj179megmCUBYmR24iUB6+zLSfD6\nxOVsuBWn5RwXnqW2TVVngjMzxBfCU03i0/8wiZ7sLgjLYxS0VS66PIo4Zbl4urOC\nSVyiBqE/BabyUONFq5HMcM5IuBqXpHXcnEAWrVUQn5jVKrXA8HhjpYgY4jO2OQq/\nOPjoZ/rG0EkC678B8ZJFu+Ce4QO1O9KDEZ/PkYRduVbclvznRbFbTjWSI5Tp9DBH\nfDrTQn8oEQ5ODp3/IrGDwcdTNB/NjNhprq7/gkOYeK0z4/mBss5+HNifz7FSlztH\ni/4+gfhqIxlmMEugKwQAUfGhLOJFmsfunXN26S6Ytr9iVFJ13vneJ4nvUb2AUkx+\nLPGWVIa11QgkZW02JjR+Y1OyNc7+wzJY0FyLV+3uI21b+V+NDa/vHkZ9j2cyyuRF\nmC6tUYN3A2hDiH7klGJuHSyZP6G0+flwrE0HAndJPRcb/yLL5RwSgqj3VSpEyCbS\nUQH1Az5T27X98MMKlchzfmZ1I2j1SzpSAzic+Vy367uLlRxVebl00Q0Kav8dvOYy\nn1QQmcNbH9pRaKZENhz3NEt3zVji69ZSA7/Xau3nhEduDQ==\n=r8jA\n-----END PGP MESSAGE-----",
"fp": "3D7C8D39E8C4DF771583D3F0A8A091FD346001CA" "fp": "3D7C8D39E8C4DF771583D3F0A8A091FD346001CA"
} }
], ],
"unencrypted_suffix": "_unencrypted", "unencrypted_suffix": "_unencrypted",
"version": "3.7.2" "version": "3.7.3"
} }
} }

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit a65be367d953846718ad37901bb08bcc78f1a6c8 Subproject commit 46de4dddbd56c60001323c393a6f44a31c0ec963

View File

@ -0,0 +1,63 @@
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}
resource "digitalocean_database_cluster" "main" {
name = var.cluster_name
engine = var.db_engine
size = var.size
region = var.digitalocean_region
node_count = var.node_count
version = var.db_version
private_network_uuid = var.vpc_id
}
resource "digitalocean_database_db" "main" {
for_each = { for db in var.databases: db.name => db }
cluster_id = digitalocean_database_cluster.main.id
name = each.key
}
locals {
base_connection_string = trimsuffix(digitalocean_database_cluster.main.uri,
"/defaultdb?sslmode=require")
}
resource "digitalocean_database_user" "default_users" {
for_each = {
for db in [for db in var.databases: db if db.create_default_superuser]:
db.name => db.name
}
cluster_id = digitalocean_database_cluster.main.id
name = each.key
provisioner "local-exec" {
command = "GRANT ALL ON DATABASE ${each.key} TO ${each.key};"
interpreter = [
"psql",
"-v", "ON_ERROR_STOP=1",
"${local.base_connection_string}/${each.key}",
"-c"
]
}
provisioner "local-exec" {
command = "GRANT ALL ON SCHEMA public TO ${each.key}"
interpreter = [
"psql",
"-v", "ON_ERROR_STOP=1",
"${local.base_connection_string}/${each.key}",
"-c"
]
}
# Note: provisioners depend on databases existing
depends_on = [digitalocean_database_db.main]
}

View File

@ -0,0 +1,7 @@
output "database_cluster" {
value = digitalocean_database_cluster.main
}
output "database_users" {
value = digitalocean_database_user.default_users
}

View File

@ -0,0 +1,35 @@
variable "cluster_name" {
type = string
}
variable "db_engine" {
type = string
}
variable "size" {
type = string
}
variable "digitalocean_region" {
type = string
}
variable "node_count" {
type = number
}
variable "databases" {
type = list(object({
name = string,
create_default_superuser = optional(bool, false),
}))
}
variable "db_version" {
type = string
}
variable "vpc_id" {
type = string
nullable = true
}

View File

@ -71,6 +71,7 @@ resource "digitalocean_reserved_ip" "control_plane" {
provisioner "local-exec" { provisioner "local-exec" {
command = "mkdir -p ${local.config_directory}" command = "mkdir -p ${local.config_directory}"
} }
provisioner "local-exec" { provisioner "local-exec" {
command = join(" ", ["talosctl", "gen", "config", command = join(" ", ["talosctl", "gen", "config",
"--output-dir=${local.config_directory}", "--output-dir=${local.config_directory}",
@ -80,6 +81,14 @@ resource "digitalocean_reserved_ip" "control_plane" {
"https://${self.ip_address}:6443" "https://${self.ip_address}:6443"
]) ])
} }
/*
* Terraform is stinky, won't let us use `local.config_directory`
provisioner "local-exec" {
command = "rm -rf ${local.config_directory}"
when = destroy
}
*/
} }
data "local_file" "controlplane" { data "local_file" "controlplane" {
@ -96,9 +105,11 @@ resource "digitalocean_droplet" "control_plane" {
name = "talos-control-plane" name = "talos-control-plane"
region = data.digitalocean_region.provided.slug region = data.digitalocean_region.provided.slug
image = var.talos_image image = var.talos_image
size = "s-2vcpu-4gb" size = var.control_plane_pool.size
backups = true
user_data = data.local_file.controlplane.content user_data = data.local_file.controlplane.content
ssh_keys = [digitalocean_ssh_key.dummy.fingerprint] ssh_keys = [digitalocean_ssh_key.dummy.fingerprint]
vpc_uuid = var.vpc_id
// talos expects the endpoint and node to be that of the machine itself, not the elastic IP // talos expects the endpoint and node to be that of the machine itself, not the elastic IP
provisioner "local-exec" { provisioner "local-exec" {
@ -117,16 +128,6 @@ resource "digitalocean_droplet" "control_plane" {
provisioner "local-exec" { provisioner "local-exec" {
command = "talosctl --talosconfig ${local.config_directory}/talosconfig bootstrap" command = "talosctl --talosconfig ${local.config_directory}/talosconfig bootstrap"
} }
/*
provisioner "local-exec" {
command = "talosctl --talosconfig ${local.config_directory}/talosconfig kubeconfig -f ${local.config_directory}/kubeconfig"
}
provisioner "local-exec" {
command = "kubectl --kubeconfig ${local.config_directory}/kubeconfig -n kube-system create configmap calico-config --from-literal=kubernetes_service_host=${digitalocean_reserved_ip.control_plane.ip_address} --from-literal=kubernetes_service_port=6443"
}
*/
} }
resource "digitalocean_reserved_ip_assignment" "control_plane" { resource "digitalocean_reserved_ip_assignment" "control_plane" {
@ -143,6 +144,7 @@ resource "digitalocean_droplet" "worker" {
size = each.value.size size = each.value.size
user_data = data.local_file.worker.content user_data = data.local_file.worker.content
ssh_keys = [digitalocean_ssh_key.dummy.fingerprint] ssh_keys = [digitalocean_ssh_key.dummy.fingerprint]
vpc_uuid = var.vpc_id
} }
# TODO(RyanSquared): Commenting this part out until I get Kustomizations built # TODO(RyanSquared): Commenting this part out until I get Kustomizations built
@ -157,14 +159,24 @@ resource "null_resource" "init-cluster" {
} }
*/ */
resource "null_resource" "configure_calico" { resource "null_resource" "generate_kubeconfig" {
depends_on = [digitalocean_droplet.worker] triggers = {
workers = join(",", [
provisioner "local-exec" { for node_name, node in digitalocean_droplet.worker: node_name
command = "talosctl --talosconfig ${local.config_directory}/talosconfig kubeconfig -f ${local.config_directory}/kubeconfig" ])
} }
provisioner "local-exec" { provisioner "local-exec" {
command = "kubectl --kubeconfig ${local.config_directory}/kubeconfig -n kube-system create configmap calico-config --from-literal=kubernetes_service_host=${digitalocean_reserved_ip.control_plane.ip_address} --from-literal=kubernetes_service_port=6443" command = "talosctl --talosconfig ${local.config_directory}/talosconfig kubeconfig --nodes ${digitalocean_droplet.control_plane.ipv4_address} -f ${local.config_directory}/kubeconfig"
} }
provisioner "local-exec" {
command = "talosctl --talosconfig ${local.config_directory}/talosconfig config node ${digitalocean_droplet.control_plane.ipv4_address} ${join(" ", [for node_name, node in digitalocean_droplet.worker: node.ipv4_address])}"
}
/*
provisioner "local-exec" {
command = "kubectl --kubeconfig ${local.config_directory}/kubeconfig -n kube-system create configmap calico-machine-config --from-literal=kubernetes_service_host=${digitalocean_reserved_ip.control_plane.ip_address} --from-literal=kubernetes_service_port=6443"
}
*/
} }

View File

@ -34,3 +34,8 @@ variable "worker_pools" {
size = optional(string, "s-2vcpu-4gb"), size = optional(string, "s-2vcpu-4gb"),
})) }))
} }
variable "vpc_id" {
type = string
default = "undefined"
}