From 68f5b62bad4d67a46ccdb1ca6156d1727012fa7b Mon Sep 17 00:00:00 2001 From: Alistair Hey Date: Thu, 15 Oct 2020 18:21:01 +0100 Subject: [PATCH 1/2] Replace templating and custom deployment with Helm This commit replaces the custom OFC installation scripts (shell script and golang) with the OFC Helm chart which is pulled from the OFC release specified in the init.yaml. This has been tested using my init.yaml taken from a working cluster and applied to a new cluster (same init.yaml) with the new deployment method using the chart Signed-off-by: Alistair Hey --- cmd/apply.go | 117 ++++++---- example.init.yaml | 4 + pkg/ingress/ingress.go | 98 --------- pkg/ingress/ingress_test.go | 29 --- pkg/stack/stack.go | 28 --- pkg/stack/stack_test.go | 30 --- pkg/tls/.gitignore | 1 - pkg/tls/issuer_test.go | 236 --------------------- pkg/tls/tls.go | 104 --------- pkg/types/types.go | 66 ++++++ scripts/deploy-cloud-components.sh | 33 +-- templates/edge-auth-dep.yml | 100 --------- templates/issue-prod.yml | 20 -- templates/k8s/ingress-auth.yml | 27 --- templates/k8s/ingress-wildcard.yml | 34 --- templates/k8s/tls/auth-domain-cert.yml | 14 -- templates/k8s/tls/issuer-prod.yml | 36 ---- templates/k8s/tls/issuer-staging.yml | 36 ---- templates/k8s/tls/wildcard-domain-cert.yml | 14 -- templates/of-builder-dep.yml | 76 ------- 20 files changed, 146 insertions(+), 957 deletions(-) delete mode 100644 pkg/ingress/ingress.go delete mode 100644 pkg/ingress/ingress_test.go delete mode 100644 pkg/tls/.gitignore delete mode 100644 pkg/tls/issuer_test.go delete mode 100644 pkg/tls/tls.go delete mode 100644 templates/edge-auth-dep.yml delete mode 100644 templates/issue-prod.yml delete mode 100644 templates/k8s/ingress-auth.yml delete mode 100644 templates/k8s/ingress-wildcard.yml delete mode 100644 templates/k8s/tls/auth-domain-cert.yml delete mode 100644 templates/k8s/tls/issuer-prod.yml delete mode 100644 templates/k8s/tls/issuer-staging.yml delete mode 100644 templates/k8s/tls/wildcard-domain-cert.yml delete mode 100644 templates/of-builder-dep.yml diff --git a/cmd/apply.go b/cmd/apply.go index 4e99347..3d36eab 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -4,6 +4,7 @@ package cmd import ( + "errors" "fmt" "io/ioutil" "log" @@ -18,13 +19,11 @@ import ( execute "github.com/alexellis/go-execute/pkg/v1" "github.com/alexellis/k3sup/pkg/config" "github.com/alexellis/k3sup/pkg/env" - "github.com/openfaas/ofc-bootstrap/pkg/ingress" "github.com/openfaas/ofc-bootstrap/pkg/stack" - "github.com/openfaas/ofc-bootstrap/pkg/tls" "github.com/openfaas/ofc-bootstrap/pkg/validators" "github.com/openfaas/ofc-bootstrap/pkg/types" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" ) func init() { @@ -141,7 +140,7 @@ func runApplyCommandE(command *cobra.Command, _ []string) error { "faas-cli version", } - validateToolsErr := validateTools(tools, additionalPaths) + validateToolsErr := validateTools(tools) if validateToolsErr != nil { panic(validateToolsErr) @@ -184,7 +183,7 @@ type Vars struct { YamlFile string } -func taskGivesStdout(tool string, additionalPaths []string) error { +func taskGivesStdout(tool string) error { parts := strings.Split(tool, " ") @@ -210,10 +209,10 @@ func taskGivesStdout(tool string, additionalPaths []string) error { return nil } -func validateTools(tools []string, additionalPaths []string) error { +func validateTools(tools []string) error { for _, tool := range tools { - err := taskGivesStdout(tool, additionalPaths) + err := taskGivesStdout(tool) if err != nil { return err } @@ -350,23 +349,12 @@ func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string } } - ingressErr := ingress.Apply(plan) - if ingressErr != nil { - log.Println(ingressErr) - } - - if plan.TLS { - tlsErr := tls.Apply(plan) - if tlsErr != nil { - log.Println(tlsErr) - } - } - fmt.Println("Creating stack.yml") planErr := stack.Apply(plan) if planErr != nil { log.Println(planErr) + return planErr } if !prefs.SkipSealedSecrets { @@ -389,6 +377,11 @@ func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string return cloneErr } + ofcValuesErr := writeOFCValuesYaml(plan) + if ofcValuesErr != nil { + return ofcValuesErr + } + deployErr := deployCloudComponents(plan, additionalPaths) if deployErr != nil { return deployErr @@ -397,33 +390,80 @@ func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string return nil } -func helmRepoAdd(name, repo string) error { - log.Printf("Adding %s helm repo\n", name) +func writeOFCValuesYaml(plan types.Plan) error { + ofcOptions := &types.OFCValues{} - task := execute.ExecTask{ - Command: "helm", - Args: []string{"repo", "add", name, repo}, - StreamStdio: true, + ofcOptions.NetworkPolicies.Enabled = plan.NetworkPolicies + + if plan.EnableOAuth { + ofcOptions.EdgeAuth.EnableOauth2 = true + ofcOptions.EdgeAuth.OauthProvider = plan.SCM + ofcOptions.EdgeAuth.ClientID = plan.OAuth.ClientId + ofcOptions.EdgeAuth.OauthProviderBaseURL = plan.OAuth.OAuthProviderBaseURL + } else { + ofcOptions.EdgeAuth.EnableOauth2 = false } - taskRes, taskErr := task.Execute() + ofcOptions.NetworkPolicies.Enabled = plan.NetworkPolicies + ofcOptions.Global.EnableECR = plan.EnableECR - if taskErr != nil { - return taskErr + if plan.TLS { + ofcOptions.TLS.IssuerType = plan.TLSConfig.IssuerType + ofcOptions.TLS.Enabled = true + ofcOptions.TLS.Email = plan.TLSConfig.Email + ofcOptions.TLS.DNSService = plan.TLSConfig.DNSService + switch ofcOptions.TLS.DNSService { + case types.CloudDNS: + ofcOptions.TLS.CloudDNS.ProjectID = plan.TLSConfig.ProjectID + case types.Cloudflare: + ofcOptions.TLS.Cloudflare.Email = plan.TLSConfig.Email + ofcOptions.TLS.Cloudflare.ProjectID = plan.TLSConfig.ProjectID + case types.Route53: + ofcOptions.TLS.Route53.AccessKeyID = plan.TLSConfig.AccessKeyID + ofcOptions.TLS.Route53.Region = plan.TLSConfig.Region + case types.DigitalOcean: + // No special config for DO DNS + default: + log.Fatalf("dns service not recognised: %s", ofcOptions.TLS.DNSService) + } + + } else { + ofcOptions.TLS.Enabled = false } - if len(taskRes.Stderr) > 0 { - log.Println(taskRes.Stderr) + if plan.CustomersSecret { + ofcOptions.Customers.CustomersSecret = true + } else { + if len(plan.CustomersURL) == 0 { + return errors.New("unable to continue without a customers secret or url") + } + ofcOptions.Customers.URL = plan.CustomersURL + } + + ofcOptions.Global.EnableECR = plan.EnableECR + ofcOptions.Global.RootDomain = plan.RootDomain + + ofcOptions.Ingress.MaxConnections = plan.IngressConfig.MaxConnections + ofcOptions.Ingress.RequestsPerMinute = plan.IngressConfig.RequestsPerMinute + yamlBytes, err := yaml.Marshal(&ofcOptions) + if err != nil { + log.Fatalf("error: %v", err) + } + filePath := "./tmp/ofc-values.yaml" + fileErr := ioutil.WriteFile(filePath, yamlBytes, 0644) + if fileErr != nil { + return fileErr } return nil } -func helmRepoAddStable() error { - log.Println("Adding stable helm repo") +func helmRepoAdd(name, repo string) error { + log.Printf("Adding %s helm repo\n", name) task := execute.ExecTask{ Command: "helm", + Args: []string{"repo", "add", name, repo}, StreamStdio: true, } @@ -660,19 +700,6 @@ func createSecrets(plan types.Plan) error { return nil } -func sealedSecretsReady() bool { - - task := execute.ExecTask{ - Command: "./scripts/get-sealedsecretscontroller.sh", - Shell: true, - StreamStdio: true, - } - - res, err := task.Execute() - fmt.Println("sealedsecretscontroller", res.ExitCode, res.Stdout, res.Stderr, err) - return res.Stdout == "1" -} - func exportSealedSecretPubCert() string { task := execute.ExecTask{ diff --git a/example.init.yaml b/example.init.yaml index ceb7ff6..96d7c23 100644 --- a/example.init.yaml +++ b/example.init.yaml @@ -333,3 +333,7 @@ enable_ingress_operator: false ### Usage: release tag, a SHA or branch name openfaas_cloud_version: 0.14.2 +## Settings for the ingress records +ingress_config: + max_connections: 20 + requests_per_minute: 600 diff --git a/pkg/ingress/ingress.go b/pkg/ingress/ingress.go deleted file mode 100644 index 2f405ea..0000000 --- a/pkg/ingress/ingress.go +++ /dev/null @@ -1,98 +0,0 @@ -package ingress - -import ( - "bytes" - "fmt" - "html/template" - "io/ioutil" - "log" - "os" - - execute "github.com/alexellis/go-execute/pkg/v1" - "github.com/openfaas/ofc-bootstrap/pkg/types" -) - -type IngressTemplate struct { - RootDomain string - TLS bool - IssuerType string -} - -// Apply templates and applies any ingress records required -// for the OpenFaaS Cloud ingress configuration -func Apply(plan types.Plan) error { - - err := apply("ingress-wildcard.yml", "ingress-wildcard", IngressTemplate{ - RootDomain: plan.RootDomain, - TLS: plan.TLS, - IssuerType: plan.TLSConfig.IssuerType, - }) - - if err != nil { - return err - } - - err1 := apply("ingress-auth.yml", "ingress-auth", IngressTemplate{ - RootDomain: plan.RootDomain, - TLS: plan.TLS, - IssuerType: plan.TLSConfig.IssuerType, - }) - - if err1 != nil { - return err1 - } - - return nil -} - -func apply(source string, name string, ingress IngressTemplate) error { - - generatedData, err := applyTemplate("templates/k8s/"+source, ingress) - if err != nil { - return fmt.Errorf("unable to read template %s (%s), error: %q", name, "templates/k8s/"+source, err) - } - - tempFilePath := "tmp/generated-ingress-" + name + ".yaml" - file, fileErr := os.Create(tempFilePath) - if fileErr != nil { - return fileErr - } - defer file.Close() - - _, writeErr := file.Write(generatedData) - file.Close() - - if writeErr != nil { - return writeErr - } - - execTask := execute.ExecTask{ - Command: "kubectl", - Args: []string{"apply", "-f", tempFilePath}, - Shell: false, - StreamStdio: true, - } - - execRes, execErr := execTask.Execute() - if execErr != nil { - return execErr - } - - log.Println(execRes.ExitCode, execRes.Stdout, execRes.Stderr) - - return nil -} - -func applyTemplate(templateFileName string, templateValues IngressTemplate) ([]byte, error) { - data, err := ioutil.ReadFile(templateFileName) - if err != nil { - return nil, err - } - t := template.Must(template.New(templateFileName).Parse(string(data))) - - buffer := new(bytes.Buffer) - - executeErr := t.Execute(buffer, templateValues) - - return buffer.Bytes(), executeErr -} diff --git a/pkg/ingress/ingress_test.go b/pkg/ingress/ingress_test.go deleted file mode 100644 index 44689f8..0000000 --- a/pkg/ingress/ingress_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package ingress - -import ( - "strings" - "testing" -) - -func Test_applyTemplateWithTLS(t *testing.T) { - templateValues := IngressTemplate{ - RootDomain: "test.com", - TLS: true, - } - - templateFileName := "../../templates/k8s/ingress-auth.yml" - - generatedValue, err := applyTemplate(templateFileName, templateValues) - want := "tls" - - if err != nil { - t.Errorf("expected no error generating template, but got %s", err.Error()) - t.Fail() - return - } - - if strings.Contains(string(generatedValue), want) == false { - t.Errorf("want generated value to contain: %q, generated was: %q", want, string(generatedValue)) - t.Fail() - } -} diff --git a/pkg/stack/stack.go b/pkg/stack/stack.go index 898ec36..bb5355f 100644 --- a/pkg/stack/stack.go +++ b/pkg/stack/stack.go @@ -50,7 +50,6 @@ type awsConfig struct { ECRRegion string } -// Apply creates `templates/gateway_config.yml` to be referenced by stack.yml func Apply(plan types.Plan) error { scheme := "http" if plan.TLS { @@ -67,7 +66,6 @@ func Apply(plan types.Plan) error { Registry: plan.Registry, RootDomain: plan.RootDomain, CustomersURL: plan.CustomersURL, - Scheme: scheme, S3: plan.S3, CustomTemplates: plan.Deployment.FormatCustomTemplates(), EnableDockerfileLang: plan.EnableDockerfileLang, @@ -105,26 +103,6 @@ func Apply(plan types.Plan) error { return dashboardConfigErr } - if plan.EnableOAuth { - ofCustomersSecretPath := "" - if plan.CustomersSecret { - ofCustomersSecretPath = "/var/secrets/of-customers/of-customers" - } - - if ofAuthDepErr := generateTemplate("edge-auth-dep", plan, authConfig{ - RootDomain: plan.RootDomain, - ClientId: plan.OAuth.ClientId, - CustomersURL: plan.CustomersURL, - Scheme: scheme, - OAuthProvider: plan.SCM, - OAuthProviderBaseURL: plan.OAuth.OAuthProviderBaseURL, - OFCustomersSecretPath: ofCustomersSecretPath, - TLSEnabled: plan.TLS, - }); ofAuthDepErr != nil { - return ofAuthDepErr - } - } - isGitHub := plan.SCM == "github" if stackErr := generateTemplate("stack", plan, stackConfig{ GitHub: isGitHub, @@ -133,12 +111,6 @@ func Apply(plan types.Plan) error { return stackErr } - if builderErr := generateTemplate("of-builder-dep", plan, builderConfig{ - ECR: plan.EnableECR, - }); builderErr != nil { - return builderErr - } - if ecrErr := generateTemplate("aws", plan, awsConfig{ ECRRegion: plan.ECRConfig.ECRRegion, }); ecrErr != nil { diff --git a/pkg/stack/stack_test.go b/pkg/stack/stack_test.go index 3a1b92f..a4e4304 100644 --- a/pkg/stack/stack_test.go +++ b/pkg/stack/stack_test.go @@ -5,36 +5,6 @@ import ( "testing" ) -func Test_applyTemplateWithAuth(t *testing.T) { - - clientID := "test_oauth_app_client_id" - customersURL := "https://raw.githubusercontent.com/test/path/CUSTOMERS" - - templateValues := authConfig{ - ClientId: clientID, - CustomersURL: customersURL, - Scheme: "http", - } - - templateFileName := "../../templates/edge-auth-dep.yml" - - generatedValue, err := applyTemplate(templateFileName, templateValues) - - if err != nil { - t.Errorf("expected no error generating template, but got %s", err.Error()) - t.Fail() - return - } - - values := []string{clientID, customersURL} - for _, want := range values { - if strings.Contains(string(generatedValue), want) == false { - t.Errorf("want generated value to contain: %q, generated was: %q", want, string(generatedValue)) - t.Fail() - } - } -} - func Test_gitlabTemplates(t *testing.T) { gitLabInstance := "https://gitlab.test.o6s.io/" diff --git a/pkg/tls/.gitignore b/pkg/tls/.gitignore deleted file mode 100644 index 1e82fc7..0000000 --- a/pkg/tls/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.yaml diff --git a/pkg/tls/issuer_test.go b/pkg/tls/issuer_test.go deleted file mode 100644 index 710ca57..0000000 --- a/pkg/tls/issuer_test.go +++ /dev/null @@ -1,236 +0,0 @@ -package tls - -import ( - "bytes" - "html/template" - "io/ioutil" - "testing" -) - -func Test_DigitalOcean_Issuer(t *testing.T) { - tlsTemplate := TLSTemplate{ - Email: "sales@openfaas.com", - IssuerType: "ClusterIssuer", - DNSService: "digitalocean", - } - - templatePath := "../../templates/k8s/tls/issuer-prod.yml" - templateData, err := ioutil.ReadFile(templatePath) - if err != nil { - t.Error(err) - return - } - - templateRes := template.Must(template.New("prod-issuer").Parse(string(templateData))) - buf := bytes.Buffer{} - - templateRes.Execute(&buf, &tlsTemplate) - - wantTemplate := `apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: letsencrypt-prod - namespace: openfaas -spec: - acme: - email: "sales@openfaas.com" - server: https://acme-v02.api.letsencrypt.org/directory - privateKeySecretRef: - name: letsencrypt-prod - solvers: - - dns01: - digitalocean: - - tokenSecretRef: - name: digitalocean-dns - key: access-token - ` - - got := string(buf.Bytes()) - if len(got) == 0 { - t.Errorf("No bytes generated from template") - t.Fail() - } - - if debugYAML { - ioutil.WriteFile("want-"+tlsTemplate.DNSService+".yaml", []byte(wantTemplate), 0700) - ioutil.WriteFile("got-"+tlsTemplate.DNSService+".yaml", []byte(got), 0700) - } - - if got != wantTemplate { - t.Errorf("Want\n`%q`\n, but got\n`%q`", wantTemplate, got) - } - -} - -func Test_Route53_Issuer(t *testing.T) { - tlsTemplate := TLSTemplate{ - Email: "sales@openfaas.com", - IssuerType: "ClusterIssuer", - DNSService: "route53", - Region: "us-east-1", - AccessKeyID: "key-id", - } - - templatePath := "../../templates/k8s/tls/issuer-prod.yml" - templateData, err := ioutil.ReadFile(templatePath) - if err != nil { - t.Error(err) - return - } - - templateRes := template.Must(template.New("prod-issuer").Parse(string(templateData))) - buf := bytes.Buffer{} - templateRes.Execute(&buf, &tlsTemplate) - - wantTemplate := `apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: letsencrypt-prod - namespace: openfaas -spec: - acme: - email: "sales@openfaas.com" - server: https://acme-v02.api.letsencrypt.org/directory - privateKeySecretRef: - name: letsencrypt-prod - solvers: - - dns01: - route53: - - region: us-east-1 - # optional if ambient credentials are available; see ambient credentials documentation - accessKeyID: key-id - secretAccessKeySecretRef: - name: "route53-credentials-secret" - key: secret-access-key - ` - - got := string(buf.Bytes()) - if len(got) == 0 { - t.Errorf("No bytes generated from template") - t.Fail() - } - - if debugYAML { - ioutil.WriteFile("want-"+tlsTemplate.DNSService+".yaml", []byte(wantTemplate), 0700) - ioutil.WriteFile("got-"+tlsTemplate.DNSService+".yaml", []byte(got), 0700) - } - - if got != wantTemplate { - t.Errorf("Want\n`%q`\n, but got\n`%q`", wantTemplate, got) - } -} - -func Test_GoogleCloudDNS_Issuer(t *testing.T) { - tlsTemplate := TLSTemplate{ - Email: "sales@openfaas.com", - IssuerType: "ClusterIssuer", - DNSService: "clouddns", - ProjectID: "project-1", - } - - templatePath := "../../templates/k8s/tls/issuer-prod.yml" - templateData, err := ioutil.ReadFile(templatePath) - if err != nil { - t.Error(err) - return - } - - templateRes := template.Must(template.New("prod-issuer").Parse(string(templateData))) - buf := bytes.Buffer{} - templateRes.Execute(&buf, &tlsTemplate) - - wantTemplate := `apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: letsencrypt-prod - namespace: openfaas -spec: - acme: - email: "sales@openfaas.com" - server: https://acme-v02.api.letsencrypt.org/directory - privateKeySecretRef: - name: letsencrypt-prod - solvers: - - dns01: - clouddns: - - project: "project-1" - serviceAccountSecretRef: - name: "clouddns-service-account" - key: service-account.json - ` - - got := string(buf.Bytes()) - if len(got) == 0 { - t.Errorf("No bytes generated from template") - t.Fail() - } - - if debugYAML { - ioutil.WriteFile("want-"+tlsTemplate.DNSService+".yaml", []byte(wantTemplate), 0700) - ioutil.WriteFile("got-"+tlsTemplate.DNSService+".yaml", []byte(got), 0700) - } - - if got != wantTemplate { - t.Errorf("Want\n`%q`\n, but got\n`%q`", wantTemplate, got) - } -} - -func Test_CloudFlare_Issuer(t *testing.T) { - tlsTemplate := TLSTemplate{ - Email: "sales@openfaas.com", - IssuerType: "ClusterIssuer", - DNSService: "cloudflare", - } - - templatePath := "../../templates/k8s/tls/issuer-prod.yml" - templateData, err := ioutil.ReadFile(templatePath) - if err != nil { - t.Error(err) - return - } - - templateRes := template.Must(template.New("prod-issuer").Parse(string(templateData))) - buf := bytes.Buffer{} - templateRes.Execute(&buf, &tlsTemplate) - - wantTemplate := `apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: letsencrypt-prod - namespace: openfaas -spec: - acme: - email: "sales@openfaas.com" - server: https://acme-v02.api.letsencrypt.org/directory - privateKeySecretRef: - name: letsencrypt-prod - solvers: - - dns01: - cloudflare: - - email: sales@openfaas.com - apiKeySecretRef: - name: cloudflare-api-key-secret - key: api-key - ` - - got := string(buf.Bytes()) - if len(got) == 0 { - t.Errorf("No bytes generated from template") - t.Fail() - } - - if debugYAML { - ioutil.WriteFile("want-"+tlsTemplate.DNSService+".yaml", []byte(wantTemplate), 0700) - ioutil.WriteFile("got-"+tlsTemplate.DNSService+".yaml", []byte(got), 0700) - } - - if got != wantTemplate { - t.Errorf("Want\n`%q`\n, but got\n`%q`", wantTemplate, got) - } -} - -var debugYAML bool diff --git a/pkg/tls/tls.go b/pkg/tls/tls.go deleted file mode 100644 index 42012b0..0000000 --- a/pkg/tls/tls.go +++ /dev/null @@ -1,104 +0,0 @@ -package tls - -import ( - "html/template" - "io/ioutil" - "log" - "os" - - execute "github.com/alexellis/go-execute/pkg/v1" - "github.com/openfaas/ofc-bootstrap/pkg/types" -) - -// TLSTemplate TLS configuration -type TLSTemplate struct { - RootDomain string - Email string - DNSService string - ProjectID string - IssuerType string - Region string - AccessKeyID string -} - -// Apply executes the plan -func Apply(plan types.Plan) error { - - tlsTemplatesList, _ := listTLSTemplates() - tlsTemplate := TLSTemplate{ - RootDomain: plan.RootDomain, - Email: plan.TLSConfig.Email, - DNSService: plan.TLSConfig.DNSService, - ProjectID: plan.TLSConfig.ProjectID, - IssuerType: plan.TLSConfig.IssuerType, - Region: plan.TLSConfig.Region, - AccessKeyID: plan.TLSConfig.AccessKeyID, - } - - for _, template := range tlsTemplatesList { - tempFilePath, tlsTemplateErr := generateTemplate(template, tlsTemplate) - if tlsTemplateErr != nil { - return tlsTemplateErr - } - - applyErr := applyTemplate(tempFilePath) - if applyErr != nil { - return applyErr - } - } - - return nil -} - -func listTLSTemplates() ([]string, error) { - - return []string{ - "issuer-prod.yml", - "issuer-staging.yml", - "wildcard-domain-cert.yml", - "auth-domain-cert.yml", - }, nil -} - -func generateTemplate(fileName string, tlsTemplate TLSTemplate) (string, error) { - tlsTemplatesPath := "templates/k8s/tls/" - - data, err := ioutil.ReadFile(tlsTemplatesPath + fileName) - if err != nil { - return "", err - } - - t := template.Must(template.New(fileName).Parse(string(data))) - tempFilePath := "tmp/generated-tls-" + fileName - file, fileErr := os.Create(tempFilePath) - if fileErr != nil { - return "", fileErr - } - defer file.Close() - - executeErr := t.Execute(file, tlsTemplate) - - if executeErr != nil { - return "", executeErr - } - - return tempFilePath, nil -} - -func applyTemplate(tempFilePath string) error { - - execTask := execute.ExecTask{ - Command: "kubectl apply -f " + tempFilePath, - Shell: false, - StreamStdio: true, - } - - execRes, execErr := execTask.Execute() - if execErr != nil { - return execErr - } - - log.Println(execRes.ExitCode, execRes.Stdout, execRes.Stderr) - - return nil -} diff --git a/pkg/types/types.go b/pkg/types/types.go index cd59f34..c294d1c 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -70,6 +70,13 @@ type Plan struct { ECRConfig ECRConfig `yaml:"ecr_config,omitempty"` CustomersSecret bool `yaml:"customers_secret,omitempty"` IngressOperator bool `yaml:"enable_ingress_operator,omitempty"` + IngressConfig IngressConfig `yaml:"ingress_config,omitempty"` +} + +// IngressConfig is for configuring Ingress type settings, like max connections +type IngressConfig struct { + MaxConnections string `yaml:"max_connections,omitempty"` + RequestsPerMinute string `yaml:"requests_per_minute,omitempty"` } // Deployment is the deployment section of YAML concerning @@ -156,3 +163,62 @@ type TLSConfig struct { type ECRConfig struct { ECRRegion string `yaml:"ecr_region,omitempty"` } + +type OFCValues struct { + EdgeAuth EdgeAuth `yaml:"edgeAuth,omitempty"` + TLS OFCTLS `yaml:"tls,omitempty"` + Ingress Ingress `yaml:"ingress,omitempty"` + Global Global `yaml:"global,omitempty"` + NetworkPolicies NetworkPolicies `yaml:"networkPolicies,omitempty"` + Customers Customers `yaml:"customers,omitempty"` +} + +type NetworkPolicies struct { + Enabled bool `yaml:"enabled,omitempty"` +} + +type EdgeAuth struct { + EnableOauth2 bool `yaml:"enableOauth2,omitempty"` + OauthProvider string `yaml:"oauthProvider,omitempty"` + OauthProviderBaseURL string `yaml:"oauthProviderBaseURL,omitempty"` + ClientID string `yaml:"clientId,omitempty"` +} + +type OFCTLS struct { + Enabled bool `yaml:"enabled"` + Email string `yaml:"email,omitempty"` + IssuerType string `yaml:"issuerType,omitempty"` + DNSService string `yaml:"dnsService,omitempty"` + Route53 OFCRoute53 `yaml:"route53,omitempty"` + Cloudflare OFCCloudflare `yaml:"cloudflare,omitempty"` + CloudDNS CloudDNSConfig `yaml:"clouddns,omitempty"` +} + +type CloudDNSConfig struct { + ProjectID string `yaml:"projectID,omitempty"` +} + +type OFCRoute53 struct { + Region string `yaml:"region,omitempty"` + AccessKeyID string `yaml:"accessKeyID,omitempty"` +} + +type OFCCloudflare struct { + Email string `yaml:"email,omitempty"` + ProjectID string `yaml:"projectID,omitempty"` +} + +type Ingress struct { + MaxConnections string `yaml:"maxConnections,omitempty"` + RequestsPerMinute string `yaml:"requestsPerMinute,omitempty"` +} + +type Customers struct { + URL string `yaml:"url,omitempty"` + CustomersSecret bool `yaml:"customersSecret,omitempty"` +} + +type Global struct { + RootDomain string `yaml:"rootDomain,omitempty"` + EnableECR bool `yaml:"enableECR,omitempty"` +} diff --git a/scripts/deploy-cloud-components.sh b/scripts/deploy-cloud-components.sh index a4af600..d90de0a 100755 --- a/scripts/deploy-cloud-components.sh +++ b/scripts/deploy-cloud-components.sh @@ -1,38 +1,17 @@ #!/bin/bash + + cp ./tmp/generated-gateway_config.yml ./tmp/openfaas-cloud/gateway_config.yml cp ./tmp/generated-github.yml ./tmp/openfaas-cloud/github.yml cp ./tmp/generated-slack.yml ./tmp/openfaas-cloud/slack.yml cp ./tmp/generated-dashboard_config.yml ./tmp/openfaas-cloud/dashboard/dashboard_config.yml cp ./tmp/generated-aws.yml ./tmp/openfaas-cloud/aws.yml -kubectl apply -f ./tmp/openfaas-cloud/yaml/core/of-builder-svc.yml - -# Update builder for any ECR secrets needed -cp ./tmp/generated-of-builder-dep.yml ./tmp/openfaas-cloud/yaml/core/of-builder-dep.yml -kubectl apply -f ./tmp/openfaas-cloud/yaml/core/of-builder-dep.yml - -kubectl apply -f ./tmp/openfaas-cloud/yaml/core/rbac-import-secrets.yml - -if [ "$ENABLE_OAUTH" = "true" ] ; then - cp ./tmp/generated-edge-auth-dep.yml ./tmp/openfaas-cloud/yaml/core/edge-auth-dep.yml - kubectl apply -f ./tmp/openfaas-cloud/yaml/core/edge-auth-dep.yml - kubectl apply -f ./tmp/openfaas-cloud/yaml/core/edge-auth-svc.yml - kubectl apply -f ./tmp/openfaas-cloud/yaml/core/edge-router-dep.yml -else - # Disable auth service by pointing the router at the echo function: - sed s/edge-auth.openfaas/echo.openfaas-fn/g ./tmp/openfaas-cloud/yaml/core/edge-router-dep.yml | kubectl apply -f - -fi - -kubectl apply -f ./tmp/openfaas-cloud/yaml/core/edge-router-svc.yml - -kubectl apply -f ./tmp/openfaas-cloud/yaml/core/edge-auth-svc.yml +cd ./tmp/openfaas-cloud -if [ "$ENABLE_NETWORK_POLICIES" = "true" ] ; then - kubectl apply -f ./tmp/openfaas-cloud/yaml/network-policy/ -fi -cd ./tmp/openfaas-cloud +helm upgrade --install --values ../ofc-values.yaml ofc-core ./chart/openfaas-cloud echo "Creating payload-secret in openfaas-fn" @@ -86,9 +65,5 @@ faas-cli deploy sleep 2 -# This `ServiceAccount` needs to be patched in place so that the function can perform create / get and update on the SealedSecret CRD: -#kubectl patch -n openfaas-fn deploy import-secrets -p '{"spec":{"template":{"spec":{"serviceAccountName":"sealedsecrets-importer-rw"}}}}' -# This is now applied through an annotation in stack.yml - # Close the kubectl port-forward kill %1 diff --git a/templates/edge-auth-dep.yml b/templates/edge-auth-dep.yml deleted file mode 100644 index 60ffa76..0000000 --- a/templates/edge-auth-dep.yml +++ /dev/null @@ -1,100 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: edge-auth - namespace: openfaas - labels: - app: edge-auth -spec: - replicas: 1 - selector: - matchLabels: - app: edge-auth - template: - metadata: - annotations: - prometheus.io.scrape: "false" - labels: - app: edge-auth - spec: - volumes: - - name: jwt-private-key - secret: - secretName: jwt-private-key - - name: jwt-public-key - secret: - secretName: jwt-public-key - - name: of-client-secret - secret: - secretName: of-client-secret - - name: of-customers - secret: - secretName: of-customers - containers: - - name: edge-auth - image: openfaas/edge-auth:0.7.1 - imagePullPolicy: Always - livenessProbe: - httpGet: - path: /healthz - port: 8080 - initialDelaySeconds: 2 - periodSeconds: 10 - timeoutSeconds: 2 - env: - - name: port - value: "8080" - - name: oauth_client_secret_path - value: "/var/secrets/of-client-secret/of-client-secret" - - name: public_key_path - value: "/var/secrets/public/key.pub" - - name: private_key_path - value: "/var/secrets/private/key" - - name: customers_path - value: "{{.OFCustomersSecretPath}}" -# Update for your configuration: - - name: client_secret # this can also be provided via a secret named of-client-secret - value: "" - - name: client_id - value: "{{.ClientId}}" - - name: oauth_provider_base_url - value: "{{.OAuthProviderBaseURL}}" - - name: oauth_provider - value: "{{.OAuthProvider}}" -# Local test config - # - name: external_redirect_domain - # value: "http://auth.system.gw.io:8081" - # - name: cookie_root_domain - # value: ".system.gw.io" - -# Community cluster config: - - name: external_redirect_domain - value: "{{.Scheme}}://auth.system.{{.RootDomain}}" - - name: cookie_root_domain - value: ".system.{{.RootDomain}}" -# This is a default and can be overridden - - name: customers_url - value: "{{.CustomersURL}}" - - name: write_debug - value: "false" - # Config for setting the cookie to "secure", set this to true for HTTPS only OAuth - - name: secure_cookie - value: "{{.TLSEnabled}}" - - - ports: - - containerPort: 8080 - protocol: TCP - volumeMounts: - - name: jwt-private-key - readOnly: true - mountPath: "/var/secrets/private/" - - name: jwt-public-key - readOnly: true - mountPath: "/var/secrets/public" - - name: of-client-secret - readOnly: true - mountPath: "/var/secrets/of-client-secret" - - name: of-customers - readOnly: true - mountPath: "/var/secrets/of-customers" diff --git a/templates/issue-prod.yml b/templates/issue-prod.yml deleted file mode 100644 index 4bb7d05..0000000 --- a/templates/issue-prod.yml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: letsencrypt-prod - namespace: default -spec: - acme: - server: https://acme-v02.api.letsencrypt.org/directory - email: your-email@gmail.com - privateKeySecretRef: - name: letsencrypt-prod - dns01: - providers: - - name: prod-dns - clouddns: - serviceAccountSecretRef: - name: clouddns-service-account - key: service-account.json - project: proj-name - diff --git a/templates/k8s/ingress-auth.yml b/templates/k8s/ingress-auth.yml deleted file mode 100644 index 8ca5f7a..0000000 --- a/templates/k8s/ingress-auth.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: openfaas-auth-ingress - namespace: openfaas - annotations: - kubernetes.io/ingress.class: "nginx" - nginx.ingress.kubernetes.io/limit-connections: "20" - nginx.ingress.kubernetes.io/limit-rpm: "600" - labels: - app: faas-netesd -spec: - {{ if .TLS }} - tls: - - hosts: - - auth.system.{{.RootDomain}} - secretName: auth-system-{{.RootDomain}}-cert - {{ end }} - rules: - - host: auth.system.{{.RootDomain}} - http: - paths: - - path: / - backend: - serviceName: edge-router - servicePort: 8080 diff --git a/templates/k8s/ingress-wildcard.yml b/templates/k8s/ingress-wildcard.yml deleted file mode 100644 index 356dc55..0000000 --- a/templates/k8s/ingress-wildcard.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: openfaas-ingress - namespace: openfaas - annotations: - kubernetes.io/ingress.class: "nginx" - nginx.ingress.kubernetes.io/limit-connections: "20" - nginx.ingress.kubernetes.io/limit-rpm: "600" - labels: - app: faas-netesd -spec: - {{ if .TLS }} - tls: - - hosts: - - '*.{{.RootDomain}}' - secretName: wildcard-{{.RootDomain}}-cert - {{ end }} - rules: - - host: '*.{{.RootDomain}}' - http: - paths: - - path: / - backend: - serviceName: edge-router - servicePort: 8080 - - host: 'gateway.{{.RootDomain}}' - http: - paths: - - path: / - backend: - serviceName: gateway - servicePort: 8080 diff --git a/templates/k8s/tls/auth-domain-cert.yml b/templates/k8s/tls/auth-domain-cert.yml deleted file mode 100644 index 5841a5d..0000000 --- a/templates/k8s/tls/auth-domain-cert.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate -metadata: - name: auth-system-{{.RootDomain}} - namespace: openfaas -spec: - secretName: auth-system-{{.RootDomain}}-cert - issuerRef: - name: letsencrypt-{{.IssuerType}} - kind: ClusterIssuer - commonName: 'auth.system.{{.RootDomain}}' - dnsNames: - - 'auth.system.{{.RootDomain}}' diff --git a/templates/k8s/tls/issuer-prod.yml b/templates/k8s/tls/issuer-prod.yml deleted file mode 100644 index 849d74a..0000000 --- a/templates/k8s/tls/issuer-prod.yml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: letsencrypt-prod - namespace: openfaas -spec: - acme: - email: "{{.Email}}" - server: https://acme-v02.api.letsencrypt.org/directory - privateKeySecretRef: - name: letsencrypt-prod - solvers: - - dns01: - {{.DNSService}}: - {{ if eq .DNSService "clouddns" }} - project: "{{.ProjectID}}" - serviceAccountSecretRef: - name: "{{.DNSService}}-service-account" - key: service-account.json - {{else if eq .DNSService "route53" }} - region: {{.Region}} - # optional if ambient credentials are available; see ambient credentials documentation - accessKeyID: {{.AccessKeyID}} - secretAccessKeySecretRef: - name: "{{.DNSService}}-credentials-secret" - key: secret-access-key - {{else if eq .DNSService "cloudflare" }} - email: {{.Email}} - apiKeySecretRef: - name: cloudflare-api-key-secret - key: api-key - {{else if eq .DNSService "digitalocean" }} - tokenSecretRef: - name: digitalocean-dns - key: access-token - {{ end }} \ No newline at end of file diff --git a/templates/k8s/tls/issuer-staging.yml b/templates/k8s/tls/issuer-staging.yml deleted file mode 100644 index 7a8563a..0000000 --- a/templates/k8s/tls/issuer-staging.yml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: letsencrypt-staging - namespace: openfaas -spec: - acme: - email: "{{.Email}}" - server: https://acme-staging-v02.api.letsencrypt.org/directory - privateKeySecretRef: - name: letsencrypt-staging - solvers: - - dns01: - {{.DNSService}}: - {{ if eq .DNSService "clouddns" }} - project: "{{.ProjectID}}" - serviceAccountSecretRef: - name: "{{.DNSService}}-service-account" - key: service-account.json - {{else if eq .DNSService "route53" }} - region: {{.Region}} - # optional if ambient credentials are available; see ambient credentials documentation - accessKeyID: {{.AccessKeyID}} - secretAccessKeySecretRef: - name: "{{.DNSService}}-credentials-secret" - key: secret-access-key - {{else if eq .DNSService "cloudflare" }} - email: {{.Email}} - apiKeySecretRef: - name: cloudflare-api-key-secret - key: api-key - {{else if eq .DNSService "digitalocean" }} - tokenSecretRef: - name: digitalocean-dns - key: access-token - {{ end }} \ No newline at end of file diff --git a/templates/k8s/tls/wildcard-domain-cert.yml b/templates/k8s/tls/wildcard-domain-cert.yml deleted file mode 100644 index c0aa111..0000000 --- a/templates/k8s/tls/wildcard-domain-cert.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate -metadata: - name: wildcard-{{.RootDomain}} - namespace: openfaas -spec: - secretName: wildcard-{{.RootDomain}}-cert - issuerRef: - name: letsencrypt-{{.IssuerType}} - kind: ClusterIssuer - commonName: '*.{{.RootDomain}}' - dnsNames: - - '*.{{.RootDomain}}' diff --git a/templates/of-builder-dep.yml b/templates/of-builder-dep.yml deleted file mode 100644 index 3eef4b7..0000000 --- a/templates/of-builder-dep.yml +++ /dev/null @@ -1,76 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: of-builder - namespace: openfaas - labels: - app: of-builder -spec: - replicas: 1 - selector: - matchLabels: - app: of-builder - template: - metadata: - annotations: - prometheus.io.scrape: "false" - labels: - app: of-builder - spec: - volumes: - - name: registry-secret - secret: - secretName: registry-secret - - name: payload-secret - secret: - secretName: payload-secret - {{ if .ECR }} - - name: aws-ecr-credentials - secret: - defaultMode: 420 - secretName: aws-ecr-credentials - {{ end }} - containers: - - name: of-builder - image: openfaas/of-builder:0.8.0 - imagePullPolicy: Always - livenessProbe: - httpGet: - path: /healthz - port: 8080 - initialDelaySeconds: 2 - periodSeconds: 10 - timeoutSeconds: 2 - env: - - name: enable_lchown - value: "true" - - name: insecure - value: "false" - - name: buildkit_url - value: "tcp://127.0.0.1:1234" - - name: "disable_hmac" - value: "false" - ports: - - containerPort: 8080 - protocol: TCP - volumeMounts: - - name: registry-secret - readOnly: true - mountPath: "/home/app/.docker/" - - name: payload-secret - readOnly: true - mountPath: "/var/openfaas/secrets/" - {{ if .ECR }} - - mountPath: /home/app/.aws/ - readOnly: true - name: aws-ecr-credentials - {{ end }} - - name: of-buildkit - args: ["--addr", "tcp://0.0.0.0:1234"] - image: moby/buildkit:v0.6.2 - imagePullPolicy: Always - ports: - - containerPort: 1234 - protocol: TCP - securityContext: - privileged: true From d06c02bab417ee2922b065068a4c997c59daba09 Mon Sep 17 00:00:00 2001 From: Alistair Hey Date: Fri, 16 Oct 2020 09:07:07 +0100 Subject: [PATCH 2/2] Allow cloud components only to be upgraded This should allow passing the --update-cloud flag which will only upgrade/install the OFC core components (chart AND stack.yaml etc) This also fixes the ClusterIssuer -> Issuer move so the secrets for DNS need to be in the issuer namespace Signed-off-by: Alistair Hey --- USER_GUIDE.md | 54 ++--------- cmd/apply.go | 61 ++++++++----- example.init.yaml | 8 +- scripts/clone-cloud-components.sh | 2 +- templates/edge-auth-dep.yml | 100 +++++++++++++++++++++ templates/issue-prod.yml | 20 +++++ templates/k8s/ingress-auth.yml | 27 ++++++ templates/k8s/ingress-wildcard.yml | 34 +++++++ templates/k8s/tls/auth-domain-cert.yml | 14 +++ templates/k8s/tls/issuer-prod.yml | 36 ++++++++ templates/k8s/tls/issuer-staging.yml | 36 ++++++++ templates/k8s/tls/wildcard-domain-cert.yml | 14 +++ templates/of-builder-dep.yml | 76 ++++++++++++++++ 13 files changed, 408 insertions(+), 74 deletions(-) create mode 100644 templates/edge-auth-dep.yml create mode 100644 templates/issue-prod.yml create mode 100644 templates/k8s/ingress-auth.yml create mode 100644 templates/k8s/ingress-wildcard.yml create mode 100644 templates/k8s/tls/auth-domain-cert.yml create mode 100644 templates/k8s/tls/issuer-prod.yml create mode 100644 templates/k8s/tls/issuer-staging.yml create mode 100644 templates/k8s/tls/wildcard-domain-cert.yml create mode 100644 templates/of-builder-dep.yml diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 12a4daf..91bf1e5 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -4,7 +4,7 @@ You will need admin access to a Kubernetes cluster, some CLI tooling and a GitHu ## Pre-reqs -This tool automates the installation of OpenFaaS Cloud on Kubernetes. Before starting you will need to install some tools and then create either a local or remote cluster. +This tool automates the installation of OpenFaaS Cloud on Kubernetes. Before starting, you will need to install some tools and then create either a local or remote cluster. For your cluster the following specifications are recommended: @@ -513,28 +513,8 @@ At this point you can also view your UI dashboard at: http://127.0.0.1:31112 ## Re-deploy the OpenFaaS Cloud functions (advanced) -If you run the step above `Access your OpenFaaS UI or API`, then you can edit settings for OpenFaaS Cloud and redeploy your functions. This is an advanced step. - -``` -cd tmp/openfaas-cloud/ - -# Edit stack.yml -# Edit github.yml or gitlab.yml -# Edit gateway_config.yml -# Edit buildshiprun_limits.yml - -# Edit aws.yml if you want to change AWS ECR settings such as the region - -# Update all functions -faas-cli deploy -f stack.yml - - -# Update AWS ECR functions if needed -faas-cli deploy -f aws.yml - -# Update a single function, such as "buildshiprun" -faas-cli deploy -f stack.yml --filter=buildshiprun -``` +Run `ofc-bootstrap` passing `--update-cloud` as a flag. +This will re-deploy the ofc helm chart using the new settings in init.yaml ## Invite your team @@ -549,29 +529,9 @@ alexellis When you want to switch to the Production issuer from staging do the following: -Flush out the staging certificates and orders +Update the staging setting in init.yaml to "prod" and re-run `ofc-bootstrap` passing `--update-cloud` as a flag. +This will re-deploy the ofc helm chart using the new settings. -```sh -kubectl delete certificates --all -n openfaas -kubectl delete secret -n openfaas -l="cert-manager.io/certificate-name" -kubectl delete order -n openfaas --all +```sh +ofc-bootstrap apply -f init.yaml --update-cloud ``` - -Now update the staging references to "prod": - -```sh -sed -i '' s/letsencrypt-staging/letsencrypt-prod/g ./tmp/generated-ingress-ingress-wildcard.yaml -sed -i '' s/letsencrypt-staging/letsencrypt-prod/g ./tmp/generated-ingress-ingress-auth.yaml -sed -i '' s/letsencrypt-staging/letsencrypt-prod/g ./tmp/generated-tls-auth-domain-cert.yml -sed -i '' s/letsencrypt-staging/letsencrypt-prod/g ./tmp/generated-tls-wildcard-domain-cert.yml -``` - -Now create the new ingress and certificates: - -```sh -kubectl apply -f ./tmp/generated-ingress-ingress-wildcard.yaml -kubectl apply -f ./tmp/generated-ingress-ingress-auth.yaml -kubectl apply -f ./tmp/generated-tls-auth-domain-cert.yml -kubectl apply -f ./tmp/generated-tls-wildcard-domain-cert.yml -``` - diff --git a/cmd/apply.go b/cmd/apply.go index 3d36eab..50a3437 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -34,6 +34,7 @@ func init() { applyCmd.Flags().Bool("skip-minio", false, "Skip Minio installation") applyCmd.Flags().Bool("skip-create-secrets", false, "Skip creating secrets") applyCmd.Flags().Bool("print-plan", false, "Print merged plan and exit") + applyCmd.Flags().Bool("update-cloud", false, "set to true to only upgrade OFC components") } var applyCmd = &cobra.Command{ @@ -158,15 +159,28 @@ func runApplyCommandE(command *cobra.Command, _ []string) error { os.MkdirAll("tmp", 0700) ioutil.WriteFile("tmp/go.mod", []byte("\n"), 0700) - fmt.Fprint(os.Stdout, "Validating registry credentials file") + fmt.Fprint(os.Stdout, "Validating registry credentials file\n") registryAuthErr := validateRegistryAuth(plan.Registry, plan.Secrets, plan.EnableECR) if registryAuthErr != nil { fmt.Fprint(os.Stderr, "error with registry credentials file. Please ensure it has been created correctly") } + cloudOnly, err := command.Flags().GetBool("update-cloud") + if err != nil { + return err + } + + if cloudOnly { + err := cloudComponentsInstall(plan) + if err != nil { + return err + } + return nil + } + start := time.Now() - err = process(plan, prefs, additionalPaths) + err = process(plan, prefs) done := time.Since(start) if err != nil { @@ -264,7 +278,7 @@ func filesExists(files []types.FileSecret) error { return nil } -func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string) error { +func process(plan types.Plan, prefs InstallPreferences) error { if plan.OpenFaaSCloudVersion == "" { plan.OpenFaaSCloudVersion = "master" @@ -297,7 +311,7 @@ func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string return err } - installIngressErr := installIngressController(plan.Ingress, additionalPaths) + installIngressErr := installIngressController(plan.Ingress) if installIngressErr != nil { log.Println(installIngressErr.Error()) return installIngressErr @@ -332,7 +346,7 @@ func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string log.Println(functionAuthErr.Error()) } - ofErr := installOpenfaas(plan.ScaleToZero, plan.IngressOperator, additionalPaths) + ofErr := installOpenfaas(plan.ScaleToZero, plan.IngressOperator) if ofErr != nil { log.Println(ofErr) } @@ -372,7 +386,16 @@ func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string } } - cloneErr := cloneCloudComponents(plan.OpenFaaSCloudVersion, additionalPaths) + err := cloudComponentsInstall(plan) + if err != nil { + return err + } + + return nil +} + +func cloudComponentsInstall(plan types.Plan) error { + cloneErr := cloneCloudComponents(plan.OpenFaaSCloudVersion) if cloneErr != nil { return cloneErr } @@ -382,11 +405,10 @@ func process(plan types.Plan, prefs InstallPreferences, additionalPaths []string return ofcValuesErr } - deployErr := deployCloudComponents(plan, additionalPaths) + deployErr := deployCloudComponents(plan) if deployErr != nil { return deployErr } - return nil } @@ -431,13 +453,10 @@ func writeOFCValuesYaml(plan types.Plan) error { ofcOptions.TLS.Enabled = false } - if plan.CustomersSecret { - ofcOptions.Customers.CustomersSecret = true - } else { - if len(plan.CustomersURL) == 0 { - return errors.New("unable to continue without a customers secret or url") - } - ofcOptions.Customers.URL = plan.CustomersURL + ofcOptions.Customers.CustomersSecret = plan.CustomersSecret + ofcOptions.Customers.URL = plan.CustomersURL + if len(plan.CustomersURL) == 0 && !plan.CustomersSecret { + return errors.New("unable to continue without a customers secret or url") } ofcOptions.Global.EnableECR = plan.EnableECR @@ -524,7 +543,7 @@ func createFunctionsAuth() error { return nil } -func installIngressController(ingress string, additionalPaths []string) error { +func installIngressController(ingress string) error { log.Println("Creating Ingress Controller") var env []string @@ -572,7 +591,7 @@ func installSealedSecrets() error { return nil } -func installOpenfaas(scaleToZero, ingressOperator bool, additionalPaths []string) error { +func installOpenfaas(scaleToZero, ingressOperator bool) error { log.Println("Creating OpenFaaS") task := execute.ExecTask{ @@ -725,7 +744,7 @@ func certManagerReady() bool { return res.Stdout == "True" } -func cloneCloudComponents(tag string, additionalPaths []string) error { +func cloneCloudComponents(tag string) error { task := execute.ExecTask{ Command: "./scripts/clone-cloud-components.sh", Shell: true, @@ -735,17 +754,15 @@ func cloneCloudComponents(tag string, additionalPaths []string) error { StreamStdio: true, } - res, err := task.Execute() + _, err := task.Execute() if err != nil { return err } - fmt.Println(res) - return nil } -func deployCloudComponents(plan types.Plan, additionalPaths []string) error { +func deployCloudComponents(plan types.Plan) error { authEnv := "" if plan.EnableOAuth { diff --git a/example.init.yaml b/example.init.yaml index 96d7c23..6fef2ba 100644 --- a/example.init.yaml +++ b/example.init.yaml @@ -104,7 +104,7 @@ secrets: value_from: "~/Downloads/do-access-token" filters: - "do_dns01" - namespace: "cert-manager" + namespace: "openfaas" ## Use Google Cloud DNS ### Create a service account for DNS management and export it @@ -114,7 +114,7 @@ secrets: value_from: "~/Downloads/service-account.json" filters: - "gcp_dns01" - namespace: "cert-manager" + namespace: "openfaas" ## Use Route 53 ### Create role and download its secret access key @@ -124,7 +124,7 @@ secrets: value_from: "~/Downloads/route53-secret-access-key" filters: - "route53_dns01" - namespace: "cert-manager" + namespace: "openfaas" ## Use Cloudflare ### Create role and download its secret access key @@ -134,7 +134,7 @@ secrets: value_from: "~/Downloads/cloudflare-secret-access-key" filters: - "cloudflare_dns01" - namespace: "cert-manager" + namespace: "openfaas" # Used by Buildkit to push images to your registry - name: "registry-secret" diff --git a/scripts/clone-cloud-components.sh b/scripts/clone-cloud-components.sh index 781ed24..bdeb8b3 100755 --- a/scripts/clone-cloud-components.sh +++ b/scripts/clone-cloud-components.sh @@ -2,7 +2,7 @@ rm -rf ./tmp/openfaas-cloud -git clone https://github.com/openfaas/openfaas-cloud ./tmp/openfaas-cloud +git clone https://github.com/openfaas/openfaas-cloud --depth 1 ./tmp/openfaas-cloud cd ./tmp/openfaas-cloud echo "Checking out openfaas/openfaas-cloud@$TAG" diff --git a/templates/edge-auth-dep.yml b/templates/edge-auth-dep.yml new file mode 100644 index 0000000..60ffa76 --- /dev/null +++ b/templates/edge-auth-dep.yml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: edge-auth + namespace: openfaas + labels: + app: edge-auth +spec: + replicas: 1 + selector: + matchLabels: + app: edge-auth + template: + metadata: + annotations: + prometheus.io.scrape: "false" + labels: + app: edge-auth + spec: + volumes: + - name: jwt-private-key + secret: + secretName: jwt-private-key + - name: jwt-public-key + secret: + secretName: jwt-public-key + - name: of-client-secret + secret: + secretName: of-client-secret + - name: of-customers + secret: + secretName: of-customers + containers: + - name: edge-auth + image: openfaas/edge-auth:0.7.1 + imagePullPolicy: Always + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 2 + periodSeconds: 10 + timeoutSeconds: 2 + env: + - name: port + value: "8080" + - name: oauth_client_secret_path + value: "/var/secrets/of-client-secret/of-client-secret" + - name: public_key_path + value: "/var/secrets/public/key.pub" + - name: private_key_path + value: "/var/secrets/private/key" + - name: customers_path + value: "{{.OFCustomersSecretPath}}" +# Update for your configuration: + - name: client_secret # this can also be provided via a secret named of-client-secret + value: "" + - name: client_id + value: "{{.ClientId}}" + - name: oauth_provider_base_url + value: "{{.OAuthProviderBaseURL}}" + - name: oauth_provider + value: "{{.OAuthProvider}}" +# Local test config + # - name: external_redirect_domain + # value: "http://auth.system.gw.io:8081" + # - name: cookie_root_domain + # value: ".system.gw.io" + +# Community cluster config: + - name: external_redirect_domain + value: "{{.Scheme}}://auth.system.{{.RootDomain}}" + - name: cookie_root_domain + value: ".system.{{.RootDomain}}" +# This is a default and can be overridden + - name: customers_url + value: "{{.CustomersURL}}" + - name: write_debug + value: "false" + # Config for setting the cookie to "secure", set this to true for HTTPS only OAuth + - name: secure_cookie + value: "{{.TLSEnabled}}" + + + ports: + - containerPort: 8080 + protocol: TCP + volumeMounts: + - name: jwt-private-key + readOnly: true + mountPath: "/var/secrets/private/" + - name: jwt-public-key + readOnly: true + mountPath: "/var/secrets/public" + - name: of-client-secret + readOnly: true + mountPath: "/var/secrets/of-client-secret" + - name: of-customers + readOnly: true + mountPath: "/var/secrets/of-customers" diff --git a/templates/issue-prod.yml b/templates/issue-prod.yml new file mode 100644 index 0000000..4bb7d05 --- /dev/null +++ b/templates/issue-prod.yml @@ -0,0 +1,20 @@ +apiVersion: cert-manager.io/v1alpha2 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod + namespace: default +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: your-email@gmail.com + privateKeySecretRef: + name: letsencrypt-prod + dns01: + providers: + - name: prod-dns + clouddns: + serviceAccountSecretRef: + name: clouddns-service-account + key: service-account.json + project: proj-name + diff --git a/templates/k8s/ingress-auth.yml b/templates/k8s/ingress-auth.yml new file mode 100644 index 0000000..8ca5f7a --- /dev/null +++ b/templates/k8s/ingress-auth.yml @@ -0,0 +1,27 @@ +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: openfaas-auth-ingress + namespace: openfaas + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/limit-connections: "20" + nginx.ingress.kubernetes.io/limit-rpm: "600" + labels: + app: faas-netesd +spec: + {{ if .TLS }} + tls: + - hosts: + - auth.system.{{.RootDomain}} + secretName: auth-system-{{.RootDomain}}-cert + {{ end }} + rules: + - host: auth.system.{{.RootDomain}} + http: + paths: + - path: / + backend: + serviceName: edge-router + servicePort: 8080 diff --git a/templates/k8s/ingress-wildcard.yml b/templates/k8s/ingress-wildcard.yml new file mode 100644 index 0000000..356dc55 --- /dev/null +++ b/templates/k8s/ingress-wildcard.yml @@ -0,0 +1,34 @@ +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: openfaas-ingress + namespace: openfaas + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/limit-connections: "20" + nginx.ingress.kubernetes.io/limit-rpm: "600" + labels: + app: faas-netesd +spec: + {{ if .TLS }} + tls: + - hosts: + - '*.{{.RootDomain}}' + secretName: wildcard-{{.RootDomain}}-cert + {{ end }} + rules: + - host: '*.{{.RootDomain}}' + http: + paths: + - path: / + backend: + serviceName: edge-router + servicePort: 8080 + - host: 'gateway.{{.RootDomain}}' + http: + paths: + - path: / + backend: + serviceName: gateway + servicePort: 8080 diff --git a/templates/k8s/tls/auth-domain-cert.yml b/templates/k8s/tls/auth-domain-cert.yml new file mode 100644 index 0000000..5841a5d --- /dev/null +++ b/templates/k8s/tls/auth-domain-cert.yml @@ -0,0 +1,14 @@ +--- +apiVersion: cert-manager.io/v1alpha2 +kind: Certificate +metadata: + name: auth-system-{{.RootDomain}} + namespace: openfaas +spec: + secretName: auth-system-{{.RootDomain}}-cert + issuerRef: + name: letsencrypt-{{.IssuerType}} + kind: ClusterIssuer + commonName: 'auth.system.{{.RootDomain}}' + dnsNames: + - 'auth.system.{{.RootDomain}}' diff --git a/templates/k8s/tls/issuer-prod.yml b/templates/k8s/tls/issuer-prod.yml new file mode 100644 index 0000000..849d74a --- /dev/null +++ b/templates/k8s/tls/issuer-prod.yml @@ -0,0 +1,36 @@ +apiVersion: cert-manager.io/v1alpha2 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod + namespace: openfaas +spec: + acme: + email: "{{.Email}}" + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-prod + solvers: + - dns01: + {{.DNSService}}: + {{ if eq .DNSService "clouddns" }} + project: "{{.ProjectID}}" + serviceAccountSecretRef: + name: "{{.DNSService}}-service-account" + key: service-account.json + {{else if eq .DNSService "route53" }} + region: {{.Region}} + # optional if ambient credentials are available; see ambient credentials documentation + accessKeyID: {{.AccessKeyID}} + secretAccessKeySecretRef: + name: "{{.DNSService}}-credentials-secret" + key: secret-access-key + {{else if eq .DNSService "cloudflare" }} + email: {{.Email}} + apiKeySecretRef: + name: cloudflare-api-key-secret + key: api-key + {{else if eq .DNSService "digitalocean" }} + tokenSecretRef: + name: digitalocean-dns + key: access-token + {{ end }} \ No newline at end of file diff --git a/templates/k8s/tls/issuer-staging.yml b/templates/k8s/tls/issuer-staging.yml new file mode 100644 index 0000000..7a8563a --- /dev/null +++ b/templates/k8s/tls/issuer-staging.yml @@ -0,0 +1,36 @@ +apiVersion: cert-manager.io/v1alpha2 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + namespace: openfaas +spec: + acme: + email: "{{.Email}}" + server: https://acme-staging-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-staging + solvers: + - dns01: + {{.DNSService}}: + {{ if eq .DNSService "clouddns" }} + project: "{{.ProjectID}}" + serviceAccountSecretRef: + name: "{{.DNSService}}-service-account" + key: service-account.json + {{else if eq .DNSService "route53" }} + region: {{.Region}} + # optional if ambient credentials are available; see ambient credentials documentation + accessKeyID: {{.AccessKeyID}} + secretAccessKeySecretRef: + name: "{{.DNSService}}-credentials-secret" + key: secret-access-key + {{else if eq .DNSService "cloudflare" }} + email: {{.Email}} + apiKeySecretRef: + name: cloudflare-api-key-secret + key: api-key + {{else if eq .DNSService "digitalocean" }} + tokenSecretRef: + name: digitalocean-dns + key: access-token + {{ end }} \ No newline at end of file diff --git a/templates/k8s/tls/wildcard-domain-cert.yml b/templates/k8s/tls/wildcard-domain-cert.yml new file mode 100644 index 0000000..c0aa111 --- /dev/null +++ b/templates/k8s/tls/wildcard-domain-cert.yml @@ -0,0 +1,14 @@ +--- +apiVersion: cert-manager.io/v1alpha2 +kind: Certificate +metadata: + name: wildcard-{{.RootDomain}} + namespace: openfaas +spec: + secretName: wildcard-{{.RootDomain}}-cert + issuerRef: + name: letsencrypt-{{.IssuerType}} + kind: ClusterIssuer + commonName: '*.{{.RootDomain}}' + dnsNames: + - '*.{{.RootDomain}}' diff --git a/templates/of-builder-dep.yml b/templates/of-builder-dep.yml new file mode 100644 index 0000000..3eef4b7 --- /dev/null +++ b/templates/of-builder-dep.yml @@ -0,0 +1,76 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: of-builder + namespace: openfaas + labels: + app: of-builder +spec: + replicas: 1 + selector: + matchLabels: + app: of-builder + template: + metadata: + annotations: + prometheus.io.scrape: "false" + labels: + app: of-builder + spec: + volumes: + - name: registry-secret + secret: + secretName: registry-secret + - name: payload-secret + secret: + secretName: payload-secret + {{ if .ECR }} + - name: aws-ecr-credentials + secret: + defaultMode: 420 + secretName: aws-ecr-credentials + {{ end }} + containers: + - name: of-builder + image: openfaas/of-builder:0.8.0 + imagePullPolicy: Always + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 2 + periodSeconds: 10 + timeoutSeconds: 2 + env: + - name: enable_lchown + value: "true" + - name: insecure + value: "false" + - name: buildkit_url + value: "tcp://127.0.0.1:1234" + - name: "disable_hmac" + value: "false" + ports: + - containerPort: 8080 + protocol: TCP + volumeMounts: + - name: registry-secret + readOnly: true + mountPath: "/home/app/.docker/" + - name: payload-secret + readOnly: true + mountPath: "/var/openfaas/secrets/" + {{ if .ECR }} + - mountPath: /home/app/.aws/ + readOnly: true + name: aws-ecr-credentials + {{ end }} + - name: of-buildkit + args: ["--addr", "tcp://0.0.0.0:1234"] + image: moby/buildkit:v0.6.2 + imagePullPolicy: Always + ports: + - containerPort: 1234 + protocol: TCP + securityContext: + privileged: true