diff --git a/.gitignore b/.gitignore index 21477d3..b707e65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -config.json +/config.json +*.crt +*.key ssh localbuild.sh build @@ -11,8 +13,7 @@ terraform-modules/*/roles terraform-modules/*/callback_plugins terraform-modules/*/ansible-playbook-wrapper -*.crt -*.key + testexe test2 rootsystem diff --git a/application-modules/hello-world/docker-compose.yml b/application-modules/hello-world/docker-compose.yml index 24724ac..b57077a 100644 --- a/application-modules/hello-world/docker-compose.yml +++ b/application-modules/hello-world/docker-compose.yml @@ -4,6 +4,11 @@ services: image: nginx networks: - servergarden-ingress + volumes: + - type: bind + source: ./nginx + target: /usr/share/nginx/html + read_only: true labels: servergarden-ingress-80-public-port: 443 servergarden-ingress-80-public-protocol: https diff --git a/application-modules/hello-world/nginx/index.html b/application-modules/hello-world/nginx/index.html new file mode 100644 index 0000000..5aa13fb --- /dev/null +++ b/application-modules/hello-world/nginx/index.html @@ -0,0 +1,83 @@ + + + + + +hello world + + + + + +
+

+ Hello, World! +

+
+
+
+
+
+ +

+ Your server is online! +

+ +
+
+ +
+
+ + + diff --git a/application-modules/servergarden-ingress/caddy/config.json b/application-modules/servergarden-ingress/caddy/config.json new file mode 100644 index 0000000..bfa2c2e --- /dev/null +++ b/application-modules/servergarden-ingress/caddy/config.json @@ -0,0 +1,10 @@ +{ + "admin": { + "disabled": false, + "listen": "unix//caddysocket/caddy.sock", + "origins": ["localhost"], + "config": { + "persist": false + } + } +} \ No newline at end of file diff --git a/application-modules/servergarden-ingress/docker-compose.yml b/application-modules/servergarden-ingress/docker-compose.yml index 20be43b..b89d3cc 100644 --- a/application-modules/servergarden-ingress/docker-compose.yml +++ b/application-modules/servergarden-ingress/docker-compose.yml @@ -3,10 +3,18 @@ services: threshold: image: sequentialread/threshold:0.0.5 command: ["-mode", "client", "-configFile", "/threshold/config/config.json"] + extra_hosts: + - "greenhouseusers.com:159.89.124.224" volumes: - type: bind source: ./threshold target: /threshold/config + + # https://giedrius.blog/2018/11/22/etc-nsswitch-conf-and-etc-hosts-woes-with-the-alpine-and-others-docker-image-and-golang/ + - type: bind + source: /etc/nsswitch.conf + target: /etc/nsswitch.conf + - type: bind source: /var/run/servergarden/threshold/ target: /threshold/socket/ diff --git a/application-modules/servergarden-ingress/threshold/config.json b/application-modules/servergarden-ingress/threshold/config.json new file mode 100644 index 0000000..538eaa5 --- /dev/null +++ b/application-modules/servergarden-ingress/threshold/config.json @@ -0,0 +1,14 @@ +{ + "DebugLog": false, + "AdminUnixSocket": "/threshold/socket/threshold.sock", + "ClientIdentifier": "odroidxu4", + "ServerAddr": "greenhouseusers.com:9056", + "UseTls": true, + "ServiceToLocalAddrMap": { + "https": "127.0.0.1:445", + "http": "127.0.0.1:80" + }, + "CaCertificateFilesGlob": "config/greenhouseusers.com_CA.crt", + "ClientTlsKeyFile": "config/odroidxu4@greenhouseusers.com.key", + "ClientTlsCertificateFile": "config/odroidxu4@greenhouseusers.com.crt" +} \ No newline at end of file diff --git a/automation/ingressController.go b/automation/ingressController.go index 54e6754..175a015 100644 --- a/automation/ingressController.go +++ b/automation/ingressController.go @@ -51,16 +51,16 @@ type CaddyServer struct { } type CaddyRoute struct { - Handle []CaddyHandler `json:"handle"` - Match []CaddyMatch `json:"match"` + Handle []CaddyHandler `json:"handle,omitempty"` + Match []CaddyMatch `json:"match,omitempty"` Terminal bool `json:"terminal"` } // https://caddyserver.com/docs/json/apps/http/servers/routes/handle/ type CaddyHandler struct { Handler string `json:"handler"` - Routes []CaddyRoute `json:"routes"` - Upstreams []CaddyUpstream `json:"upstreams"` + Routes []CaddyRoute `json:"routes,omitempty"` + Upstreams []CaddyUpstream `json:"upstreams,omitempty"` } // https://caddyserver.com/docs/json/apps/http/servers/routes/handle/reverse_proxy/ diff --git a/configuration/configuration.go b/configuration/configuration.go index 05d7e08..628b82d 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -68,6 +68,7 @@ const DOCKER_SOCKET = "/var/run/docker.sock" const THRESHOLD_SOCKET = "/var/run/servergarden/threshold/threshold.sock" const CADDY_SOCKET = "/var/run/servergarden/caddy/caddy.sock" const CADDY_DATA = "/var/lib/servergarden/caddy/data/" +const THRESHOLD_DATA = "/var/lib/servergarden/threshold/" const TERRAFORM_APPLY_STATUS_UPDATE_INTERVAL_SECONDS = 5 func GET_ANSIBLE_WRAPPER_FILES() []string { diff --git a/main.go b/main.go index 3312957..2161116 100644 --- a/main.go +++ b/main.go @@ -252,10 +252,18 @@ func main() { log.Printf("rootsystem docker-compose failed") } else { time.Sleep(5 * time.Second) - err = automation.IngressConfig(config) - if err != nil { - log.Printf("rootsystem IngressConfig failed: %+v", err) + + for { + err = automation.IngressConfig(config) + if err != nil { + log.Printf("rootsystem IngressConfig failed: %+v", err) + } else { + log.Printf("rootsystem IngressConfig success") + } + + time.Sleep(30 * time.Second) } + } } } diff --git a/pki/pki.go b/pki/pki.go index 718a4e9..eba7b4d 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "log" "os" + "path" "path/filepath" "time" @@ -33,6 +34,7 @@ func BuildTLSCertsForThreshold( clientCA := fmt.Sprintf("%s_CA", clientId) domainCA := fmt.Sprintf("%s_CA", domain) + certsBackupLocation := configuration.THRESHOLD_DATA thresholdServerConfigRole := filepath.Join( workingDirectory, configuration.ANSIBLE_ROLES, @@ -50,12 +52,13 @@ func BuildTLSCertsForThreshold( ) for _, path := range []string{ + certsBackupLocation, thresholdServerConfigRole, thresholdClientConfigMount, thresholdRegisterClientWithServerConfigRole, } { if _, err := os.Stat(path); os.IsNotExist(err) { - err = os.Mkdir(path, 0600) + err = os.MkdirAll(path, 0600) if err != nil { return errors.Wrap(err, "BuildTLSCertsForThreshold(): failed trying to ensure files folder exists in ansible role") } @@ -77,7 +80,7 @@ func BuildTLSCertsForThreshold( // if the file was not already uploaded to object storage, that must mean // we are the first node to run -- therefore we must create and upload it if notFound { - log.Println("BuildTLSCertsForThreshold(): creating threshold server CA") + log.Println("BuildTLSCertsForThreshold(): creating threshold server CA / key pair ") // Create a CA for the server's key/cert err = pki.Sign( @@ -165,7 +168,7 @@ func BuildTLSCertsForThreshold( // since it runs on cloud, on someone elses computer } else { - log.Println("BuildTLSCertsForThreshold(): using existing threshold server CA") + log.Println("BuildTLSCertsForThreshold(): using threshold server CA / key pair from object storage") err = ioutil.WriteFile(domainCACertLocalPath, domainCACertFile.Content, 0600) if err != nil { @@ -192,7 +195,12 @@ func BuildTLSCertsForThreshold( } // Create A CA for this client if it doesn't already exist - clientCAFilePath := filepath.Join(thresholdRegisterClientWithServerConfigRole, fmt.Sprintf("%s.crt", clientCA)) + clientEmail := fmt.Sprintf("%s@%s", clientId, domain) + clientCAFilename := fmt.Sprintf("%s.crt", clientCA) + clientCertFilename := fmt.Sprintf("%s.crt", clientEmail) + clientKeyFilename := fmt.Sprintf("%s.key", clientEmail) + + clientCAFilePath := filepath.Join(certsBackupLocation, clientCAFilename) _, statErr := os.Stat(clientCAFilePath) log.Printf("BuildTLSCertsForThreshold(): file '%s' exists: %t\n", clientCAFilePath, !os.IsNotExist(statErr)) @@ -215,7 +223,7 @@ func BuildTLSCertsForThreshold( return errors.Wrap(err, "BuildTLSCertsForThreshold(): failed creating CA") } - err = saveBundle(pki, clientCA, clientCA, false, thresholdRegisterClientWithServerConfigRole) + err = saveBundle(pki, clientCA, clientCA, false, certsBackupLocation) if err != nil { return errors.Wrap(err, "BuildTLSCertsForThreshold(): saveBundle():") } @@ -226,7 +234,6 @@ func BuildTLSCertsForThreshold( } // Create Threshold client certificates - clientEmail := fmt.Sprintf("%s@%s", clientId, domain) err = pki.Sign( clientCASigner, &easypki.Request{ @@ -243,7 +250,7 @@ func BuildTLSCertsForThreshold( return errors.Wrap(err, "BuildTLSCertsForThreshold(): failed creating Threshold client certificate") } - err = saveBundle(pki, clientCA, clientEmail, true, thresholdClientConfigMount) + err = saveBundle(pki, clientCA, clientEmail, true, certsBackupLocation) if err != nil { return errors.Wrap(err, "BuildTLSCertsForThreshold(): saveBundle():") } @@ -251,6 +258,20 @@ func BuildTLSCertsForThreshold( log.Println("BuildTLSCertsForThreshold(): using existing threshold client CA") } + err = copyFile(path.Join(thresholdClientConfigMount, clientCertFilename), path.Join(certsBackupLocation, clientCertFilename)) + if err != nil { + return errors.Wrap(err, "BuildTLSCertsForThreshold(): failed copying cert for threshold client") + } + err = copyFile(path.Join(thresholdClientConfigMount, clientKeyFilename), path.Join(certsBackupLocation, clientKeyFilename)) + if err != nil { + return errors.Wrap(err, "BuildTLSCertsForThreshold(): failed copying key for threshold client") + } + + err = copyFile(path.Join(thresholdRegisterClientWithServerConfigRole, clientCAFilename), path.Join(certsBackupLocation, clientCAFilename)) + if err != nil { + return errors.Wrap(err, "BuildTLSCertsForThreshold(): failed copying client CA cert for threshold server") + } + return nil } @@ -320,3 +341,11 @@ func getSubject(commonName string) pkix.Name { CommonName: commonName, } } + +func copyFile(dst, src string) error { + bytes, err := ioutil.ReadFile(src) + if err != nil { + return err + } + return ioutil.WriteFile(dst, bytes, 0600) +}