This image is meant to be used as sidecar for external-dns and implements a custom DNS provider. The custom provider is in fact 2 providers, and AWS one and a Cloudflare one, configured to be used in Cloudflare Zero Trust setup.
It can be installed with bitnami external-dns chart with a values.yaml like:
provider: webhook
policy: sync
interval: "1m"
sources:
- ingress
domainFilters:
- mydomain.com
registry: "txt"
txtPrefix: "reg-"
txtOwnerId: k8s-ext-dns-custom
logLevel: info
logFormat: text
extraArgs:
webhook-provider-url: http://localhost:8888
aws:
credentials:
accessKey: "AKIA123..."
secretKey: "abc123..."
region: eu-west-1
zoneType: public
apiRetries: 3
preferCNAME: true
cloudflare:
apiToken: "abc123..."
custom:
image: bunnyshell/external-dns-custom:v0.14.1
secretName: &custom-secret-name external-dns-custom
awsTargetSuffix: .cdn.cloudflare.net
cloudflareTargetOverride: abc-123.cfargotunnel.com
sidecars:
|-
- name: ext-dns-custom
image: {{ .Values.custom.image }}
imagePullPolicy: Always
args:
- --metrics-address=:7879 # use another port than the main container
{{- if .Values.logLevel }}
- --log-level={{ .Values.logLevel }}
{{- end }}
{{- if .Values.logFormat }}
- --log-format={{ .Values.logFormat }}
{{- end }}
{{- range .Values.domainFilters }}
- --domain-filter={{ . }}
{{- end }}
{{- range .Values.excludeDomains }}
- --exclude-domains={{ . }}
{{- end }}
{{- if .Values.regexDomainFilter }}
- --regex-domain-filter={{ .Values.regexDomainFilter }}
{{- end }}
{{- if .Values.regexDomainExclusion }}
- --regex-domain-exclusion={{ .Values.regexDomainExclusion }}
{{- end }}
{{- range .Values.zoneNameFilters }}
- --zone-name-filter={{ . }}
{{- end }}
{{- range .Values.zoneIdFilters }}
- --zone-id-filter={{ . }}
{{- end }}
- --policy={{ .Values.policy }}
- --registry={{ .Values.registry }}
- --interval={{ .Values.interval }}
{{- if or (ne .Values.registry "aws-sd" ) .Values.forceTxtOwnerId }}
{{- if .Values.txtOwnerId }}
- --txt-owner-id={{ .Values.txtOwnerId }}
{{- end }}
{{- end }}
{{- if eq .Values.registry "txt" }}
{{- if .Values.txtPrefix }}
- --txt-prefix={{ .Values.txtPrefix }}
{{- end }}
{{- if .Values.txtSuffix }}
- --txt-suffix={{ .Values.txtSuffix }}
{{- end }}
{{- end }}
# AWS arguments
{{- if .Values.aws.apiRetries }}
- --aws-api-retries={{ .Values.aws.apiRetries }}
{{- end }}
- --aws-zone-type={{ .Values.aws.zoneType }}
{{- if .Values.aws.assumeRoleArn }}
- --aws-assume-role={{ .Values.aws.assumeRoleArn }}
{{- end }}
{{- if .Values.aws.batchChangeSize }}
- --aws-batch-change-size={{ .Values.aws.batchChangeSize }}
{{- end }}
{{- if .Values.aws.zonesCacheDuration }}
- --aws-zones-cache-duration={{ .Values.aws.zonesCacheDuration }}
{{- end }}
{{- range .Values.aws.zoneTags }}
- --aws-zone-tags={{ . }}
{{- end }}
{{- if .Values.aws.preferCNAME }}
- --aws-prefer-cname
{{- end }}
{{- if .Values.aws.dynamodbTable }}
- --dynamodb-table={{ .Values.aws.dynamodbTable }}
{{- end }}
{{- if .Values.aws.dynamodbRegion }}
- --dynamodb-region={{ .Values.aws.dynamodbRegion }}
{{- end }}
{{- if and (kindIs "bool" .Values.aws.evaluateTargetHealth) (not .Values.aws.evaluateTargetHealth) }}
- --no-aws-evaluate-target-health
{{- end }}
# Cloudflare arguments
{{- if .Values.cloudflare.proxied }}
- --cloudflare-proxied
{{- end }}
# args for custom provider
- --webhook-server # act like a 3rd party provider (not as controller); main container should be set on provider=webhook
- --source=fake # ignored in webhook-server setup but required; this one is preferred as it does nothing extra
- --provider=custom # specially crafted provider with desired logic inside
- --custom-aws-target-suffix={{ .Values.custom.awsTargetSuffix }} # all AWS R53 DNS records will point to target = hostname + this suffix; should be .cloudflare.net
- --custom-cf-target-override={{ .Values.custom.cloudflareTargetOverride }} # all CloudFlare DNS records will point to this target; should be the tunnel domain
env:
# AWS environment variables
{{- if .Values.aws.region }}
- name: AWS_DEFAULT_REGION
value: {{ .Values.aws.region }}
{{- end }}
{{- if .Values.aws.roleArn }}
- name: AWS_CONFIG_FILE
value: {{ .Values.aws.credentials.mountPath }}/config
{{- end }}
{{- if and .Values.aws.credentials.secretKey .Values.aws.credentials.accessKey (not (include "external-dns.aws-credentials-secret-ref-defined" . )) }}
- name: AWS_SHARED_CREDENTIALS_FILE
value: {{ .Values.aws.credentials.mountPath }}/credentials
{{- end }}
{{- if (include "external-dns.aws-credentials-secret-ref-defined" . ) }}
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ .Values.aws.credentials.accessKeyIDSecretRef.name }}
key: {{ .Values.aws.credentials.accessKeyIDSecretRef.key }}
- name: AWS_SECRET_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.aws.credentials.secretAccessKeySecretRef.name }}
key: {{ .Values.aws.credentials.secretAccessKeySecretRef.key }}
{{- end }}
# Cloudflare environment variables
- name: CF_API_TOKEN
valueFrom:
secretKeyRef:
name: {{ .Values.custom.secretName }}
key: cloudflare_api_token
optional: true
- name: CF_API_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.custom.secretName }}
key: cloudflare_api_key
optional: true
- name: CF_API_EMAIL
value: {{ .Values.cloudflare.email | quote }}
{{- if and .Values.txtEncrypt.enabled }}
- name: TXT_AES_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: {{ template "external-dns.txtEncryptKeySecretName" . }}
key: txt_aes_encryption_key
{{- end }}
ports:
- containerPort: 8888 # port on which external-dns acts as a 3rd party provider (hardcoded)
name: webhook
{{- if .Values.resources }}
resources: {{- toYaml .Values.resources | nindent 12 }}
{{- else if ne .Values.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.resourcesPreset) | nindent 12 }}
{{- end }}
volumeMounts:
{{- if and (or (and .Values.aws.credentials.secretKey .Values.aws.credentials.accessKey) .Values.aws.credentials.secretName) (not (include "external-dns.aws-credentials-secret-ref-defined" . )) }}
# AWS mountPath(s)
- name: aws-credentials # volume mount just like when provider=aws; add the volume in Helm at extraVolumes
mountPath: {{ .Values.aws.credentials.mountPath }}
readOnly: true
{{- end }}
extraDeploy:
- |
{{- if eq .Values.provider "webhook" }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.custom.secretName }}
namespace: {{ .Release.Namespace | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.secretAnnotations .Values.commonAnnotations }}
{{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.secretAnnotations .Values.commonAnnotations ) "context" . ) }}
annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
type: Opaque
data:
credentials: {{ include "external-dns.aws-credentials" . | b64enc | quote }}
{{- if .Values.aws.region }}
config: {{ include "external-dns.aws-config" . | b64enc | quote }}
{{- end }}
{{- if .Values.cloudflare.apiToken }}
cloudflare_api_token: {{ .Values.cloudflare.apiToken | b64enc | quote }}
{{- else }}
cloudflare_api_key: {{ required "cloudflare.apiKey is required if cloudflare.apiToken is not provided" .Values.cloudflare.apiKey | b64enc | quote }}
{{- end }}
{{- end }}
extraVolumes:
# AWS volume(s)
- name: aws-credentials
secret:
secretName: *custom-secret-name
Content type
Image
Digest
sha256:c0c8127b2…
Size
52 MB
Last updated
over 2 years ago
docker pull bunnyshell/external-dns-custom:v0.14.1