diff --git a/.gitignore b/.gitignore index 83392c2..d848940 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ _test icon vendor _out +bin/buildversion.exe diff --git a/Dockerfile b/Dockerfile index 9bdd3e0..3c777e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,17 @@ FROM golang:1.21-alpine3.18 AS build_deps -RUN apk add --no-cache git +# Let scripts know we're running in Docker (useful for containerised development) +ENV RUNNING_IN_DOCKER true +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ="Africa/Johannesburg" + +# Set up ZSH and our preferred terminal environment for containers +RUN apk add --no-cache git WORKDIR /workspace COPY go.mod . + COPY go.sum . RUN go mod download @@ -19,6 +26,21 @@ FROM alpine:3.18 RUN apk add --no-cache ca-certificates +RUN apk add --no-cache bash bind-tools coreutils krb5 +COPY ./config/bash.sh /root/.bashrc +#COPY ./config/krb5.conf /etc +RUN chown -R root:root /root/.bashrc && \ + /bin/bash /root/.bashrc +RUN apk add --no-cache alpine-conf && \ + setup-timezone -z Africa/Johannesburg +# chmod 0644 /etc/krb5.conf + +#RUN mkdir -p /app +#COPY ./config/updatedns.sh /app +#RUN chmod 0744 /app/updatedns.sh + COPY --from=build /workspace/webhook /usr/local/bin/webhook ENTRYPOINT ["webhook"] + + diff --git a/Makefile b/Makefile index 8c68374..289381a 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,11 @@ bin/buildversion.exe: cmd/buildversion.go go build -o bin/buildversion.exe cmd/buildversion.go set TMP="C:\Users\Chris\AppData\Local\Temp" +#bin/cert-manager-webhook-sthome.exe: dependencies version.txt +# set TMP="C:\Temp\gotemp" +# go build -o bin/cert-manager-webhook-sthome.exe +# set TMP="C:\Users\Chris\AppData\Local\Temp" + version.txt: bin/buildversion.exe dependencies bin/buildversion.exe @@ -42,16 +47,11 @@ _test/kubebuilder-$(KUBEBUILDER_VERSION)-$(OS)-$(ARCH)/etcd _test/kubebuilder-$( clean: rm -r _test $(OUT) -.PHONY: package -package: rendered-manifest.yaml - helm package deploy\sthome-webhook -d \\\truenas\Shared_data\Chris\clusterissuer\charts\ - .PHONY: build -build: rendered-manifest.yaml dependencies version.txt - docker build -t "$(IMAGE_NAME):$(shell head -n 1 version.txt)" . - docker tag $(IMAGE_NAME) "docker.io/stuurmcp/$(IMAGE_NAME):$(shell head -n 1 version.txt)" - docker image push "stuurmcp/$(IMAGE_NAME):$(shell head -n 1 version.txt)" - helm package deploy\sthome-webhook -d \\\truenas\Shared_data\Chris\clusterissuer\charts\ +build: rendered-manifest.yaml dependencies bin/buildversion.exe version.txt + docker build --pull --rm -f "Dockerfile" -t "stuurmcp/$(IMAGE_NAME):latest" -t "stuurmcp/$(IMAGE_NAME):$(shell head -n 1 version.txt)" "." + docker image push "docker.io/stuurmcp/$(IMAGE_NAME):$(shell head -n 1 version.txt)" + helm package deploy/sthome-webhook -d //truenas/Shared_data/Chris/clusterissuer/charts/ .PHONY: rendered-manifest.yaml rendered-manifest.yaml: $(OUT)/rendered-manifest.yaml diff --git a/cmd/buildversion.go b/cmd/buildversion.go index a63ef3a..13cf8e8 100644 --- a/cmd/buildversion.go +++ b/cmd/buildversion.go @@ -10,23 +10,21 @@ import ( ) const ( - version = "0.0.3-alpha" + version = "0.0.4-alpha" chartfile = "./deploy/sthome-webhook/Chart.yaml" valuesfile = "./deploy/sthome-webhook/values.yaml" tagprefix = " tag: " - versiontxt = "./version.txt" + vertxtfile = "./version.txt" apiVersion = "v1" description = "Cert-Manager webhook for sthome" name = "sthome-webhook" ) var ( - mfimagetag string - vfimagetag string - buildTime string - appVersion string - longversion string - versiontext string + buildTime string + appVersion string + longversion string + multilineversion string ) func main() { @@ -46,13 +44,12 @@ func main() { bNum, _ := strconv.Atoi(vLines[2]) bNum++ longversion = version + "." + fmt.Sprint(bNum) - mfimagetag = longversion appVersion = "v" + longversion // Generate a single string to write back to the file - versiontext = longversion + "\n" + buildTime + "\n" + fmt.Sprint(bNum) + multilineversion = longversion + "\n" + buildTime + "\n" + fmt.Sprint(bNum) chartStr := "apiVersion: " + apiVersion + "\nappVersion: " + appVersion + "\ndescription: " + description + "\nname: " + name + "\nversion: " + longversion + "\n" // Write the data back to the file. - _ = os.WriteFile(versiontxt, []byte(versiontext), 0777) + _ = os.WriteFile(vertxtfile, []byte(multilineversion), 0777) _ = os.WriteFile(chartfile, []byte(chartStr), 0777) replacetxtfilelines(valuesfile, tagprefix, tagprefix+longversion) } diff --git a/config/bash.sh b/config/bash.sh new file mode 100644 index 0000000..49c7ec4 --- /dev/null +++ b/config/bash.sh @@ -0,0 +1,29 @@ +# ~/.bashrc: executed by bash(1) for non-login shells. +# +# Note: PS1 and umask are already set in /etc/profile. You should not +# need this unless you want different defaults for root. +# PS1='${debian_chroot:+($debian_chroot)}\h:\w\$ ' +# umask 022 +# +# You may uncomment the following lines if you want `ls' to be colorized: +# export LS_OPTIONS='--color=auto' +# eval "$(dircolors)" +# alias ls='ls $LS_OPTIONS' +# alias ll='ls $LS_OPTIONS -l' +# alias l='ls $LS_OPTIONS -lA' +# +alias h='fc -l' +alias j=jobs +alias m=$PAGER +alias ll='ls -laFo' +alias l='ls -l' +alias g='egrep -i' +alias dnsupd=/acme/updatedns.sh +# +# Some more alias to avoid making mistakes: +# alias rm='rm -i' +# alias cp='cp -i' +# alias mv='mv -i' +export PATH=/root/bin:$PATH:/acme +export FRONTEND=noninteractive +export TZ=Africa/Johannesburg \ No newline at end of file diff --git a/config/zsh.sh b/config/zsh.sh new file mode 100644 index 0000000..bc1379d --- /dev/null +++ b/config/zsh.sh @@ -0,0 +1,34 @@ +HISTFILE=~/.zsh-histfile +SAVEHIST=1000 +setopt APPEND_HISTORY + +PROMPT="%n@%m[%40<...<%~%<<]%(!.#.$) " + +bindkey "^[[A" up-line-or-search +bindkey "^[[F" end-of-line +bindkey "^[[H" beginning-of-line +bindkey "^[[3~" delete-char + +# Enable the builtin emacs(1) command line editor in sh(1), +# e.g. C-a -> beginning-of-line. +set -o emacs + +# Uncomment this and comment the above to enable the builtin vi(1) command +# line editor in sh(1), e.g. ESC to go into visual mode. +# set -o vi + + +# some useful aliases +alias h='fc -l' +alias j=jobs +alias m=$PAGER +alias ll='ls -laFo' +alias l='ls -l' +alias g='egrep -i' +alias dnsupd=/acme/updatedns.sh + +# # be paranoid +# alias cp='cp -ip' +# alias mv='mv -i' +# alias rm='rm -i' +export PATH=/root/bin:$PATH diff --git a/deploy/sthome-webhook/Chart.yaml b/deploy/sthome-webhook/Chart.yaml index 1e9c8f6..374e0c0 100644 --- a/deploy/sthome-webhook/Chart.yaml +++ b/deploy/sthome-webhook/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: v0.0.3-alpha.42 +appVersion: v0.0.4-alpha.86 description: Cert-Manager webhook for sthome name: sthome-webhook -version: 0.0.3-alpha.42 +version: 0.0.4-alpha.86 diff --git a/deploy/sthome-webhook/templates/deployment.yaml b/deploy/sthome-webhook/templates/deployment.yaml index 8322f66..4ec0088 100644 --- a/deploy/sthome-webhook/templates/deployment.yaml +++ b/deploy/sthome-webhook/templates/deployment.yaml @@ -54,12 +54,26 @@ spec: - name: certs mountPath: /tls readOnly: true + - name: scriptdir + mountPath: /acme + readOnly: false + - name: workdir + mountPath: /workdir + readOnly: false resources: {{ toYaml .Values.resources | indent 12 }} volumes: - name: certs secret: secretName: {{ include "sthome-webhook.servingCertificate" . }} + - name: scriptdir + hostPath: + path: {{ .Values.host.scriptdir }} + - name: workdir + hostPath: + path: {{ .Values.host.workdir}} + + {{- with .Values.nodeSelector }} nodeSelector: {{ toYaml . | indent 8 }} diff --git a/deploy/sthome-webhook/values.yaml b/deploy/sthome-webhook/values.yaml index 99e4e7b..ac11491 100644 --- a/deploy/sthome-webhook/values.yaml +++ b/deploy/sthome-webhook/values.yaml @@ -31,7 +31,7 @@ clusterIssuer: image: repository: stuurmcp/cert-manager-webhook-sthome #repository: wstat.sthome.net:5000/cert-manager-webhook-sthome - tag: 0.0.3-alpha.42 + tag: 0.0.4-alpha.86 #pullPolicy should be IfNotPresent. Set to Always for testing purposes pullPolicy: IfNotPresent @@ -47,6 +47,10 @@ pki: caDuration: 43800h # 5y servingCertificateDuration: 8760h # 1y +host: + workdir: /mnt/stpool1/scripts/acme/cert-manager-webhook-sthome + scriptdir: /mnt/stpool1/scripts/acme + secret: accessKey: "" secretKey: "" diff --git a/sthome/shell.go b/sthome/shell.go index 252e13f..5904752 100644 --- a/sthome/shell.go +++ b/sthome/shell.go @@ -1,39 +1,45 @@ package sthome import ( - "log" "os" "os/exec" - "os/user" + + //"bytes" "k8s.io/klog/v2" ) -func Execute(dir string, script string, command []string) (bool, error) { - currentUser, err := user.Current() - if err != nil { - log.Fatalf("CZ: Unable to get current user: %s", err) - } - klog.InfoS("CZ: Executing ", "user", currentUser.Name, "script", command) - cmd := &exec.Cmd{ - Dir: dir, - Path: script, - Args: command, - Stdout: os.Stdout, - Stderr: os.Stderr, - } +type saveOutput struct { + buffer []byte +} - err = cmd.Run() +func (so *saveOutput) Write(p []byte) (n int, err error) { + so.buffer = append(so.buffer, p...) + return os.Stdout.Write(p) +} + +func Execute(shell string, command []string) (bool, error) { + var so saveOutput + //var buffer bytes.Buffer + /* + currentUser, err := user.Current() + if err != nil { + klog.Fatalf("CZ: Unable to get current user: %s", err) + } + klog.Infof("CZ: Executing as user %s : %s %v\n", currentUser.Name, shell, command) + */ + cmd := &exec.Cmd{ + Path: shell, + Args: command, + } + cmd.Stdin = os.Stdin + cmd.Stdout = &so //&buffer + cmd.Stderr = os.Stderr + err := cmd.Run() if err != nil { - klog.Errorf("CZ: Script run return error: %s\n", err) + klog.Errorf("Script return error: %s\n%s\n", err, string(so.buffer)) return false, err } - /* - err = cmd.Wait() - if err != nil { - klog.Errorf("CZ: Script Wait return error: %s\n", err) - return false, err - } - */ + klog.Infof("Script returned success:\n%s\n", string(so.buffer)) return true, nil } diff --git a/sthome/solver_local.go b/sthome/solver_local.go index a0a26a0..b047f59 100644 --- a/sthome/solver_local.go +++ b/sthome/solver_local.go @@ -2,6 +2,7 @@ package sthome import ( "fmt" + "net" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -13,8 +14,13 @@ import ( const ( providerName = "sthome" - dnsUpdaterScriptDir = "/mnt/stpool1/scripts/acme/" - dnsUpdaterScriptCmd = "updatedns.sh" + shell = "/bin/bash" + dnsUpdaterScriptCmd = "/acme/updatedns.sh" + + dnsserver_net = "10.0.0.15" + dnsserver_lan = "192.168.2.1" + hostserver_net = "truenas.sthome.net" + hostserver_lan = "truenas.sthome.lan" ) // LocalDNSProviderSolver implements the provider-specific logic needed to @@ -73,21 +79,39 @@ func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error } */ // TODO: do something more useful with the decoded configuration - fmt.Printf("CZ: Decoded configuration %v", cfg) - klog.InfoS("CZ: presenting record for ", ch.DNSName, ch.ResolvedFQDN, "domain", domainName) + klog.Infof("Decoded configuration %v\n", cfg) + klog.Infof("Presenting record for %s, ch: %s, domain: %s", ch.DNSName, ch.ResolvedFQDN, domainName) // TODO: convert shell script to golang - + localip := getOutboundIP(dnsserver_net) // shell command - command := []string{ + settxtcommand := []string{ + shell, dnsUpdaterScriptCmd, - "arg1=-set", - "arg2=.net", - fmt.Sprintf("arg3=%s", ch.DNSName), - "arg4=TXT", - fmt.Sprintf("arg5=%s", ch.Key), + "-set", + ".net", + ch.DNSName, + "TXT", + ch.Key, + "-v", + "-l", + localip, } - success, _ := Execute(dnsUpdaterScriptDir, dnsUpdaterScriptCmd, command) - klog.InfoS("CZ: Execute set returned", "success", success) + unsetcnamecommand := []string{ + shell, + dnsUpdaterScriptCmd, + "-unset", + ".net", + ch.DNSName, + "CNAME", + hostserver_net, + "-v", + "-l", + localip, + } + success, _ := Execute(shell, unsetcnamecommand) + klog.Infof("Execute unset CNAME returned success: %t", success) + success, _ = Execute(shell, settxtcommand) + klog.Infof("Execute set TXT returned success: %t", success) return nil } @@ -99,18 +123,36 @@ func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error // concurrently. func (loc *LocalDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error { // TODO: add code that deletes a record from the DNS provider's console - + localip := getOutboundIP(dnsserver_net) // shell command - command := []string{ + unsetxtcommand := []string{ + shell, dnsUpdaterScriptCmd, - "arg1=-unset", - "arg2=.net", - fmt.Sprintf("arg3=%s", ch.DNSName), - "arg4=TXT", - fmt.Sprintf("arg5=%s", ch.Key), + "-unset", + ".net", + ch.DNSName, + "TXT", + ch.Key, + "-v", + "-l", + localip, } - success, _ := Execute(dnsUpdaterScriptDir, dnsUpdaterScriptCmd, command) - klog.InfoS("CZ: Execute unset returned", "success", success) + setcnamecommand := []string{ + shell, + dnsUpdaterScriptCmd, + "-set", + ".net", + ch.DNSName, + "CNAME", + hostserver_net, + "-v", + "-l", + localip, + } + success, _ := Execute(shell, unsetxtcommand) + klog.Infof("Execute unset TXT returned success: %t", success) + success, _ = Execute(shell, setcnamecommand) + klog.Infof("Execute set CNAME returned success: %t", success) return nil } @@ -141,3 +183,17 @@ func extractDomainName(zone string) string { } return util.UnFqdn(authZone) } + +// Get preferred outbound ip of this machine +func getOutboundIP(dest string) string { + conn, err := net.Dial("udp", dest+":80") + if err != nil { + klog.Errorf("net.Dial error: %s", err) + return "0.0.0.0" + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP.String() +} diff --git a/version.txt b/version.txt index bce13ee..c828762 100644 --- a/version.txt +++ b/version.txt @@ -1,3 +1,3 @@ -0.0.3-alpha.42 -20240330-0218 -42 \ No newline at end of file +0.0.4-alpha.86 +20240331-2359 +86 \ No newline at end of file