Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ build-cli-mac: ## Build the Mac CLI

build-cli: clean build-cli-linux build-cli-mac ## Build the CLI

init-package: ## Create the zarf init package
init-package: ## Create the zarf init package, macos "brew install coreutils" first
$(ZARF_BIN) package create --confirm
mv zarf-init.tar.zst build
cd build && sha256sum -b zarf* > zarf.sha256
Expand Down
36 changes: 36 additions & 0 deletions assets/manifests/traefik/traefik.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: traefik
namespace: kube-system
spec:
chart: https://%{KUBERNETES_API}%/static/charts/traefik-9.18.2.tgz
targetNamespace: kube-system
valuesContent: |-
rbac:
enabled: true
ports:
websecure:
tls:
enabled: true
podAnnotations:
prometheus.io/port: "8082"
prometheus.io/scrape: "true"
providers:
kubernetesIngress:
publishedService:
enabled: true
priorityClassName: "system-cluster-critical"
image:
name: "rancher/library-traefik"
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"

Empty file added assets/misc/empty-file
Empty file.
12 changes: 6 additions & 6 deletions assets/misc/registries.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
mirrors:
registry.dso.mil:
endpoint:
- "https://127.0.0.1"
- "https://###ZARF_TARGET_ENDPOINT###"
registry1.dso.mil:
endpoint:
- "https://127.0.0.1"
- "https://###ZARF_TARGET_ENDPOINT###"
docker.io:
endpoint:
- "https://127.0.0.1"
- "https://###ZARF_TARGET_ENDPOINT###"
registry-1.docker.io:
endpoint:
- "https://127.0.0.1"
- "https://###ZARF_TARGET_ENDPOINT###"
ghcr.io:
endpoint:
- "https://127.0.0.1"
- "https://###ZARF_TARGET_ENDPOINT###"
registry.opensource.zalan.do:
endpoint:
- "https://127.0.0.1"
- "https://###ZARF_TARGET_ENDPOINT###"
File renamed without changes.
14 changes: 13 additions & 1 deletion cli/cmd/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package cmd

import (
"fmt"
"os"
"regexp"

"github.com/defenseunicorns/zarf/cli/config"
"github.com/defenseunicorns/zarf/cli/internal/utils"

"github.com/spf13/cobra"
Expand All @@ -15,7 +18,16 @@ var destroyCmd = &cobra.Command{
Short: "Tear it all down, we'll miss you Zarf...",
Run: func(cmd *cobra.Command, args []string) {
burn()
_, _ = utils.ExecCommand(nil, "/usr/local/bin/k3s-remove.sh")
_ = os.Remove(config.ZarfStatePath)
pattern := regexp.MustCompile(`(?mi)zarf-clean-.+\.sh$`)
scripts := utils.RecursiveFileList("/usr/local/bin", pattern)
// Iterate over al matching zarf-clean scripts and exec them
for _, script := range scripts {
// Run the matched script
_, _ = utils.ExecCommand(true, nil, script)
// Try to remove the script, but ignore any errors
_ = os.Remove(script)
}
burn()
},
}
Expand Down
177 changes: 137 additions & 40 deletions cli/cmd/initialize.go
Original file line number Diff line number Diff line change
@@ -1,79 +1,176 @@
package cmd

import (
"net"
"os"
"path/filepath"

"github.com/defenseunicorns/zarf/cli/internal/k3s"
"github.com/defenseunicorns/zarf/cli/config"
"github.com/defenseunicorns/zarf/cli/internal/packager"

"github.com/defenseunicorns/zarf/cli/internal/pki"
"github.com/defenseunicorns/zarf/cli/internal/utils"

"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var initOptions = k3s.InstallOptions{}
const invalidHostMessage = "The hostname provided (%v) was not a valid hostname. The hostname can only contain: 'a-z', 'A-Z', '0-9', '-', and '.' characters as defined by RFC-1035. If using localhost, you must use the 127.0.0.1.\n"

var initOptions = packager.InstallOptions{}
var state = config.ZarfState{
Kind: "ZarfState",
}

// initCmd represents the init command
var initCmd = &cobra.Command{
Use: "init",
Short: "Deploys the gitops service or appliance cluster on a clean linux box",
Long: "Flags are only required if running via automation, otherwise the init command will prompt you for your configuration choices",
Run: func(cmd *cobra.Command, args []string) {

if !initOptions.Confirmed {
var confirm bool
prompt := &survey.Confirm{
Message: "⚠️ This will initialize a new Zarf deployment on this machine which will make changes to your filesystem. You should not run zarf init more than once without first running zarf destroy. Do you want to continue?",
}
_ = survey.AskOne(prompt, &confirm)
if !confirm {
// Gracefully exit because they didn't want to play after all :-/
os.Exit(0)
}
}

handleTLSOptions()
k3s.Install(initOptions)
pki.HandlePKI()
packager.Install(&initOptions)
},
}

func handleTLSOptions() {
// Check to see if the certpaths or host entries are set as flags first
if initOptions.PKI.CertPublicPath == "" && initOptions.PKI.Host == "" {
// Check for cert paths provided via automation (both required)
func hasCertPaths() bool {
return state.TLS.CertPrivatePath != "" && state.TLS.CertPublicPath != ""
}

const Generate = 0
// Ask user if they will be importing or generating certs, return true if importing certs
func promptIsImportCerts() bool {
var mode int

var tlsMode int
if hasCertPaths() {
return true
}

// Determine flow for generate or import
modePrompt := &survey.Select{
Message: "Will Zarf be generating a TLS chain or importing an existing ingress cert?",
Options: []string{
"Generate TLS chain with an ephemeral CA",
"Import user-provided cert keypair",
},
if initOptions.Confirmed {
// Assume generate on confirmed without cert paths
return false
}

// Determine flow for generate or import
modePrompt := &survey.Select{
Message: "Will Zarf be generating a TLS chain or importing an existing ingress cert?",
Options: []string{
"Generate TLS chain with an ephemeral CA",
"Import user-provided cert keypair",
},
}
_ = survey.AskOne(modePrompt, &mode)

return mode == 1
}

// Ask user for the public and private key paths to import into the cluster
func promptCertPaths() {
prompt := &survey.Input{
Message: "Enter a file path to the ingress public key",
Suggest: func(toComplete string) []string {
// Give some suggestions to users
files, _ := filepath.Glob(toComplete + "*")
return files
},
}
_ = survey.AskOne(prompt, &state.TLS.CertPublicPath, survey.WithValidator(survey.Required))

prompt.Message = "Enter a file path to the ingress private key"
_ = survey.AskOne(prompt, &state.TLS.CertPrivatePath, survey.WithValidator(survey.Required))
}

// Ask user for the hostname or ip if not provided via automation and validate the input
func promptAndValidateHost() {
if state.TLS.Host == "" {
if initOptions.Confirmed {
// Fail if host is not provided on confirm
logrus.Fatalf(invalidHostMessage, state.TLS.Host)
}
_ = survey.AskOne(modePrompt, &tlsMode)

if tlsMode == Generate {
// Generate mode requires a host entry
prompt := &survey.Input{
Message: "Enter a host DNS entry or IP Address for the cluster ingress",
}
_ = survey.AskOne(prompt, &initOptions.PKI.Host, survey.WithValidator(survey.Required))
} else {
// Import mode requires the public and private key paths
prompt := &survey.Input{
Message: "Enter a file path to the ingress public key",
Suggest: func(toComplete string) []string {
// Give some suggestions to users
files, _ := filepath.Glob(toComplete + "*")
return files
},
}
_ = survey.AskOne(prompt, &initOptions.PKI.CertPublicPath, survey.WithValidator(survey.Required))
// If not provided, always ask for a host entry to avoid having to guess which entry in a cert if provided
prompt := &survey.Input{
Message: "Enter a host DNS entry or IP Address for the cluster ingress. If using localhost, use 127.0.0.1",
Suggest: func(toComplete string) []string {
var suggestions []string
// Create a list of IPs to add to the suggestion box
interfaces, err := net.InterfaceAddrs()
if err == nil {
for _, iface := range interfaces {
// Conver the CIRD to the IP string if valid
ip, _, _ := net.ParseCIDR(iface.String())
if iface.String() != "" {
suggestions = append(suggestions, ip.String())
}
}
}
// Add the localhost hostname as well
hostname, _ := os.Hostname()
if hostname != "" {
suggestions = append(suggestions, hostname)
}

return suggestions
},
}
err := survey.AskOne(prompt, &state.TLS.Host, survey.WithValidator(survey.Required))
if err != nil && err.Error() == os.Interrupt.String() {
// Handle CTRL+C
os.Exit(0)
}
}

prompt.Message = "Enter a file path to the ingress private key"
_ = survey.AskOne(prompt, &initOptions.PKI.CertPrivatePath, survey.WithValidator(survey.Required))
if !utils.ValidHostname(state.TLS.Host) {
// When hitting an invalid hostname...
if initOptions.Confirmed {
// ...if using automation end it all
logrus.Fatalf(invalidHostMessage, state.TLS.Host)
}
// ...otherwise, warn user, reset the field, and cycle the function
logrus.Warnf(invalidHostMessage, state.TLS.Host)
state.TLS.Host = ""
promptAndValidateHost()
}
if !utils.CheckHostName(initOptions.PKI.Host) {
logrus.Fatalf("The hostname provided (%v) was not a valid hostname. The hostname can only contain: 'a-z', 'A-Z', '0-9', '-', and '.' characters.\n", initOptions.PKI.Host)
}

func handleTLSOptions() {

// Get and validate host
promptAndValidateHost()

// Get the cert path if this is an import
if promptIsImportCerts() && !hasCertPaths() {
promptCertPaths()
}

// Persist the config the ZarfState
if err := config.WriteState(state); err != nil {
logrus.Debug(err)
logrus.Fatal("Unable to save the zarf state file.")
}
}

func init() {

rootCmd.AddCommand(initCmd)
initCmd.Flags().BoolVar(&initOptions.Confirmed, "confirm", false, "Confirm the install without prompting")
initCmd.Flags().StringVar(&initOptions.PKI.Host, "host", "", "Specify the host or IP for the gitops service ingress. E.g. host=10.10.10.5 or host=gitops.domain.com")
initCmd.Flags().StringVar(&initOptions.PKI.CertPublicPath, "server-crt", "", "Path to the server public key if not generating unique PKI")
initCmd.Flags().StringVar(&initOptions.PKI.CertPrivatePath, "server-key", "", "Path to the server private key if not generating unique PKI")
initCmd.Flags().StringVar(&state.TLS.Host, "host", "", "Specify the host or IP for the gitops service ingress. E.g. host=10.10.10.5 or host=gitops.domain.com")
initCmd.Flags().StringVar(&state.TLS.CertPublicPath, "server-crt", "", "Path to the server public key if not generating unique PKI")
initCmd.Flags().StringVar(&state.TLS.CertPrivatePath, "server-key", "", "Path to the server private key if not generating unique PKI")
initCmd.Flags().StringVar(&initOptions.Components, "components", "", "Comma-separated list of components to install. Adding this flag will skip the init prompts for which components to install")
}
32 changes: 21 additions & 11 deletions cli/cmd/pki.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package cmd

import (
"github.com/AlecAivazis/survey/v2"
"github.com/defenseunicorns/zarf/cli/config"
"github.com/defenseunicorns/zarf/cli/internal/pki"
"github.com/defenseunicorns/zarf/cli/internal/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var pkiOptions = utils.PKIConfig{}
var tempState config.ZarfState

var pkiCmd = &cobra.Command{
Use: "pki",
Expand All @@ -19,27 +21,35 @@ var pkiRegenerate = &cobra.Command{
Short: "Regenerate the pki certs for the cluster ingress",
Run: func(cmd *cobra.Command, args []string) {
// Prompt for a hostname if it wasn't provided as a command flag
if pkiOptions.Host == "" {
if tempState.TLS.Host == "" {
prompt := &survey.Input{
Message: "Enter a host DNS entry or IP Address for the gitops service ingress",
Message: "Enter a host DNS entry or IP Address for the gitops service ingress. If using localhost, use 127.0.0.1",
}
_ = survey.AskOne(prompt, &pkiOptions.Host, survey.WithValidator(survey.Required))
_ = survey.AskOne(prompt, &tempState.TLS.Host, survey.WithValidator(survey.Required))
}

// Verify the hostname provided is valid
if !utils.CheckHostName(pkiOptions.Host) {
logrus.Fatalf("The hostname provided (%v) was not a valid hostname. The hostname can only contain: 'a-z', 'A-Z', '0-9', '-', and '.' characters.\n", pkiOptions.Host)
if !utils.ValidHostname(tempState.TLS.Host) {
logrus.Fatalf(invalidHostMessage, tempState.TLS.Host)
}

utils.GeneratePKI(pkiOptions)
pki.GeneratePKI()
if err := config.WriteState(state); err != nil {
logrus.Debug(err)
logrus.Fatal("Unable to save the zarf state file.")
}
},
}

var pkiImport = &cobra.Command{
Use: "import",
Short: "Import an existing key pair for the cluster ingress",
Run: func(cmd *cobra.Command, args []string) {
utils.HandlePKI(pkiOptions)
pki.HandlePKI()
if err := config.WriteState(state); err != nil {
logrus.Debug(err)
logrus.Fatal("Unable to save the zarf state file.")
}
},
}

Expand All @@ -48,8 +58,8 @@ func init() {
pkiCmd.AddCommand(pkiRegenerate)
pkiCmd.AddCommand(pkiImport)

pkiRegenerate.Flags().StringVar(&pkiOptions.Host, "host", "", "Specify the host or IP for the gitops service ingress")
pkiRegenerate.Flags().StringVar(&tempState.TLS.Host, "host", "", "Specify the host or IP for the gitops service ingress")

pkiImport.Flags().StringVar(&pkiOptions.CertPublicPath, "server-crt", "", "Path to the server public key if not generating unique PKI")
pkiImport.Flags().StringVar(&pkiOptions.CertPrivatePath, "server-key", "", "Path to the server private key if not generating unique PKI")
pkiImport.Flags().StringVar(&tempState.TLS.CertPublicPath, "server-crt", "", "Path to the server public key if not generating unique PKI")
pkiImport.Flags().StringVar(&tempState.TLS.CertPrivatePath, "server-key", "", "Path to the server private key if not generating unique PKI")
}
Loading