Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(all) Add support of Selectel DNS #1

Merged
merged 18 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
project_name: external-dns-stackit-webhook
project_name: external-dns-selectel-webhook
snapshot:
name_template: '{{ .Tag }}-SNAPSHOT'
builds:
- id: external-dns-stackit-webhook
- id: external-dns-selectel-webhook
goos:
- linux
- windows
Expand All @@ -11,7 +11,7 @@ builds:
- amd64
- arm64
main: ./cmd/webhook
binary: external-dns-stackit-webhook
binary: external-dns-selectel-webhook
env:
- CGO_ENABLED=0
ldflags:
Expand All @@ -36,7 +36,7 @@ archives:
- goos: windows
format: zip
dockers:
- id: external-dns-stackit-webhook
- id: external-dns-selectel-webhook
use: buildx
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}:{{ .Tag }}"
Expand All @@ -46,7 +46,7 @@ dockers:
goarch: amd64
build_flag_templates:
- --label=org.opencontainers.image.title={{ .ProjectName }}
- --label=org.opencontainers.image.description=stackit DNS webhook for external-dns
- --label=org.opencontainers.image.description=selectel DNS webhook for external-dns
- --label=org.opencontainers.image.url=https://{{ .Env.GITHUB_SERVER_URL }}/{{ .Env.GITHUB_REPOSITORY}}
- --label=org.opencontainers.image.source=https://{{ .Env.GITHUB_SERVER_URL }}/{{ .Env.GITHUB_REPOSITORY}}
- --label=org.opencontainers.image.version={{ .Version }}
Expand Down
37 changes: 0 additions & 37 deletions CONTRIBUTING.md

This file was deleted.

4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM gcr.io/distroless/static-debian11:nonroot

COPY external-dns-stackit-webhook /external-dns-stackit-webhook
COPY external-dns-selectel-webhook /external-dns-selectel-webhook

ENTRYPOINT ["/external-dns-stackit-webhook"]
ENTRYPOINT ["/external-dns-selectel-webhook"]
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ GOLANGCI_VERSION = 1.53.3
LICENCES_IGNORE_LIST = $(shell cat licenses/licenses-ignore-list.txt)

VERSION ?= 0.0.1
IMAGE_TAG_BASE ?= stackitcloud/external-dns-stackit-webhook
IMAGE_TAG_BASE ?= selectel/external-dns-selectel-webhook
IMG ?= $(IMAGE_TAG_BASE):$(VERSION)

BUILD_VERSION ?= $(shell git branch --show-current)
Expand All @@ -17,7 +17,7 @@ download:

.PHONY: build
build:
CGO_ENABLED=0 go build -ldflags "-s -w" -o ./bin/external-dns-stackit-webhook -v cmd/webhook/main.go
CGO_ENABLED=0 go build -ldflags "-s -w" -o ./bin/external-dns-selectel-webhook -v cmd/webhook/main.go

.PHONY: docker-build
docker-build:
Expand Down Expand Up @@ -67,7 +67,7 @@ $(GO_RELEASER):

.PHONY: release-check
release-check: $(GO_RELEASER) ## Check if the release will work
GITHUB_SERVER_URL=github.com GITHUB_REPOSITORY=stackitcloud/external-dns-stackit-webhook REGISTRY=$(REGISTRY) IMAGE_NAME=$(IMAGE_NAME) $(GO_RELEASER) release --snapshot --clean --skip-publish
GITHUB_SERVER_URL=github.com GITHUB_REPOSITORY=selectel/external-dns-selectel-webhook REGISTRY=$(REGISTRY) IMAGE_NAME=$(IMAGE_NAME) $(GO_RELEASER) release --snapshot --clean --skip-publish

GO_LICENSES = bin/go-licenses
$(GO_LICENSES):
Expand Down
160 changes: 34 additions & 126 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,37 @@
# STACKIT Webhook - ExternalDNS
# Selectel Webhook - ExternalDNS

[![GoTemplate](https://img.shields.io/badge/go/template-black?logo=go)](https://github.com/golang-standards/project-layout)
[![CI](https://github.com/stackitcloud/external-dns-stackit-webhook/actions/workflows/main.yml/badge.svg)](https://github.com/stackitcloud/external-dns-stackit-webhook/actions/workflows/main.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/stackitcloud/external-dns-stackit-webhook)](https://goreportcard.com/report/github.com/stackitcloud/external-dns-stackit-webhook)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![GitHub release](https://img.shields.io/github/release/stackitcloud/external-dns-stackit-webhook.svg)](https://github.com/stackitcloud/external-dns-stackit-webhook/releases)
[![Last Commit](https://img.shields.io/github/last-commit/stackitcloud/external-dns-stackit-webhook/main.svg)](https://github.com/stackitcloud/external-dns-stackit-webhook/commits/main)
[![GitHub issues](https://img.shields.io/github/issues/stackitcloud/external-dns-stackit-webhook.svg)](https://github.com/stackitcloud/external-dns-stackit-webhook/issues)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/stackitcloud/external-dns-stackit-webhook.svg)](https://github.com/stackitcloud/external-dns-stackit-webhook/pulls)
[![GitHub stars](https://img.shields.io/github/stars/stackitcloud/external-dns-stackit-webhook.svg?style=social&label=Star&maxAge=2592000)](https://github.com/stackitcloud/external-dns-stackit-webhook/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/stackitcloud/external-dns-stackit-webhook.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/stackitcloud/external-dns-stackit-webhook/network)
[![CI](https://github.com/selectel/external-dns-selectel-webhook/actions/workflows/main.yml/badge.svg)](https://github.com/selectel/external-dns-selectel-webhook/actions/workflows/main.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/selectel/external-dns-selectel-webhook)](https://goreportcard.com/report/github.com/selectel/external-dns-selectel-webhook)
[![GitHub release](https://img.shields.io/github/release/selectel/external-dns-selectel-webhook.svg)](https://github.com/selectel/external-dns-selectel-webhook/releases)
[![Last Commit](https://img.shields.io/github/last-commit/selectel/external-dns-selectel-webhook/main.svg)](https://github.com/selectel/external-dns-selectel-webhook/commits/main)
[![GitHub issues](https://img.shields.io/github/issues/selectel/external-dns-selectel-webhook.svg)](https://github.com/selectel/external-dns-selectel-webhook/issues)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/selectel/external-dns-selectel-webhook.svg)](https://github.com/selectel/external-dns-selectel-webhook/pulls)
[![GitHub stars](https://img.shields.io/github/stars/selectel/external-dns-selectel-webhook.svg?style=social&label=Star&maxAge=2592000)](https://github.com/selectel/external-dns-selectel-webhook/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/selectel/external-dns-selectel-webhook.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/selectel/external-dns-selectel-webhook/network)

ExternalDNS serves as an add-on for Kubernetes designed to automate the management of Domain Name System (DNS)
records for Kubernetes services by utilizing various DNS providers. While Kubernetes traditionally manages DNS
records internally, ExternalDNS augments this functionality by transferring the responsibility of DNS records
management to an external DNS provider such as STACKIT. Consequently, the STACKIT webhook enables the management
of your STACKIT domains within your Kubernetes cluster using
management to an external DNS provider such as Selectel. Consequently, the Selectel webhook enables the management
of your Selectel domains within your Kubernetes cluster using
[ExternalDNS](https://github.com/kubernetes-sigs/external-dns).

For utilizing ExternalDNS with STACKIT, it is mandatory to establish a STACKIT project, a service account
For utilizing ExternalDNS with Selectel, it is mandatory to establish a Selectel project, a service account
within the project, generate an authentication token for the service account, authorize the service account
to create and read dns zones, and finally, establish a STACKIT zone.
to create and read dns zones, and finally, establish a Selectel zone.

## Kubernetes Deployment

The STACKIT webhook is presented as a standard Open Container Initiative (OCI) image released in the
[GitHub container registry](https://github.com/stackitcloud/external-dns-stackit-webhook/pkgs/container/external-dns-stackit-webhook).
The Selectel webhook is presented as a standard Open Container Initiative (OCI) image released in the
[GitHub container registry](https://github.com/selectel/external-dns-selectel-webhook/pkgs/container/external-dns-selectel-webhook).
The deployment is compatible with all Kubernetes-supported methods. The subsequent example
demonstrates the deployment as a
[sidecar container](https://kubernetes.io/docs/concepts/workloads/pods/#workload-resources-for-managing-pods)
within the ExternalDNS pod.

```shell
# We create a Secret from an auth token. Alternatively, you can also
# use keys to authenticate the webhook - see "Authentication" below.
kubectl create secret generic external-dns-stackit-webhook --from-literal=auth-token='<Your-Token>'
```shell
kubectl create secret generic external-dns-webhook --from-literal=password='<Service-User-Password>'
```

```shell
Expand Down Expand Up @@ -178,10 +175,12 @@ spec:
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65534
image: ghcr.io/stackitcloud/external-dns-stackit-webhook:v0.2.0
image: ghcr.io/selectel/external-dns-selectel-webhook:v0.1.0
imagePullPolicy: IfNotPresent
args:
- --project-id=c158c736-0300-4044-95c4-b7d404279b35 # your project id
- --account-id=000000 # your account id
- --username=Username # your service user's name
ports:
- name: http
protocol: TCP
Expand All @@ -205,136 +204,45 @@ spec:
successThreshold: 1
timeoutSeconds: 5
env:
- name: AUTH_TOKEN
- name: PASSWORD
valueFrom:
secretKeyRef:
name: external-dns-stackit-webhook
key: auth-token
name: external-dns-webhook
ormequ marked this conversation as resolved.
Show resolved Hide resolved
key: password
EOF
```

## Configuration

The configuration of the STACKIT webhook can be accomplished through command line arguments and environment variables.
The configuration of the Selectel webhook can be accomplished through command line arguments and environment variables.
Below are the options that are available.

- `--project-id`/`PROJECT_ID` (required): Specifies the project id of the STACKIT project.
- `--auth-token`/`AUTH_TOKEN` (required if `auth-key-path` is not set): Defines the authentication token for the STACKIT API. Mutually exclusive with 'auth-key-path'.
- `--auth-key-path`/`AUTH_KEY_PATH` (required if `auth-token` is not set): Defines the file path of the service account key for the STACKIT API. Mutually exclusive with 'auth-token'.
- `--project-id`/`PROJECT_ID` (required): Specifies the project id to authorize.
- `--account-id`/`ACCOUNT_ID` (required): Specifies the account id to authorize.
- `--username`/`USERNAME` (required): Specifies the username of your service user to authorize.
- `--password`/`PASSWORD` (required): Specifies the password of your service user to authorize.
- `--worker`/`WORKER` (optional): Specifies the number of workers to employ for querying the API. Given that we
need to iterate over all zones and records, it can be parallelized. However, it is important to avoid
setting this number excessively high to prevent receiving 429 rate limiting from the API (default 10).
- `--base-url`/`BASE_URL` (optional): Identifies the Base URL for utilizing the API (
default "https://dns.api.stackit.cloud").
default "https://api.selectel.ru/domains/v2"). The full list of Selectel API URLs you can see [here](https://developers.selectel.ru/docs/control-panel/urls/).
- `--auth-url`/`AUTH_URL` (optional): Identifies the URL for utilizing the API to receive keystone-token (
default "https://cloud.api.selcloud.ru/identity/v3").
- `--api-port`/`API_PORT` (optional): Specifies the port to listen on (default 8888).
- `--domain-filter`/`DOMAIN_FILER` (optional): Establishes a filter for DNS zone names (default []).
- `--dry-run`/`DRY_RUN` (optional): Specifies whether to perform a dry run (default false).
- `--log-level`/`LOG_LEVEL` (optional): Defines the log level (default "info"). Possible values are: debug, info, warn,
error.

## FAQ

### 1. Issue with Creating Service using External DNS Annotation

If your zone is `example.runs.onstackit.cloud` and you're trying to create a service with the following external DNS
annotation:

```yaml
apiVersion: v1
kind: Service
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: example.runs.onstackit.cloud
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/component: controller
name: nginx-ingress-controller
namespace: nginx-ingress-controller
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ipFamilyPolicy: SingleStack
ipFamilies:
- IPv4
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: nginx
app.kubernetes.io/name: ingress-nginx
```

<b>Why isn't it working?</b>

<b>Answer</b>: The External DNS will try to create a TXT record named `a-example.runs.onstackit.cloud`, which will fail
because you can't establish a record outside the zone. The solution is to use a name that's within the zone, such as
`nginx.example.runs.onstackit.cloud`.

### 2. Issues with Creating Ingresses not in the Zone

For a project containing the zone `example.runs.onstackit.cloud`, suppose you've created these two ingress:

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
name: example-ingress-external-dns
namespace: default
spec:
rules:
- host: test.example.runs.onstackit.cloud
http:
paths:
- backend:
service:
name: example
port:
number: 80
path: /
pathType: Prefix
- host: test.example.stackit.rocks
http:
paths:
- backend:
service:
name: example
port:
number: 80
path: /
pathType: Prefix
```

<b>Why isn't it working?</b>

<b>Answer</b>: External DNS will attempt to establish a record set for `test.example.stackit.rocks`. As the zone
`example.stackit.rocks` isn't within the project, it'll fail. There are two potential fixes:

- Incorporate the zone `example.stackit.rocks` into the project.
- Adjust the domain filter to `example.runs.onstackit.cloud` by setting the domain filter
flag `--domain-filter="example.runs.onstackit.cloud"`. This will exclude `test.example.stackit.rocks` and only
generate
the record set for `test.example.runs.onstackit.cloud`.

## Development

Run the app:

```bash
export BASE_URL="https://dns.api.stackit.cloud"
export PROJECT_ID="c158c736-0300-4044-95c4-b7d404279b35"
export AUTH_TOKEN="your-auth-token"
export ACCOUNT_ID="123456"
export USERNAME="username"
export PASSWORD ="password"

make run
```
Expand Down
Loading