From fc977ea1903bdf42f3009e27b71efa520e6d845e Mon Sep 17 00:00:00 2001 From: Marc Boorshtein Date: Sun, 27 Oct 2024 17:24:30 -0400 Subject: [PATCH] Updated OpenUnison, dashboard, kubevirt manager, and prometheus (#81) * add port 443 to the loca talos cluster * fix the way port is exposed * for #78 ingress-nginx deploys. if its in code spaces, it deploys on 10443. * for #78 update kube dashboard for version 7.x keeping dashboard capability separated from openunison so that ic an be used without it. * Added gum for input, collecting github info, deploying openunison. need get service names and localhost ingresss working. * for #78 adding port forwarders for openunison, dashboard, api server * for #79 added better automation for the openunison config. also fixed the dashboard integration * for #79 add localhost ingress chart * for #79 moved helm chart, removed dashboard release name from the certificate secret * for #79 added OpenUnison docs for GitHub * began configuring kubevirt ui * for #80 deploy kubevrit * for #79 intial implementation working. need to do some refactoring and docs * for #78 #79 refactored to line up with the refactor * for #79 moved result group into the helm chart --- .devcontainer/devcontainer.json | 5 +- Taskfile.yaml | 63 +++++- docs/OPENUNISON.md | 74 +++++-- docs/images/https.png | Bin 0 -> 407898 bytes docs/images/ports.png | Bin 0 -> 363244 bytes docs/images/public.png | Bin 0 -> 380352 bytes pulumi/__main__.py | 80 ++++--- pulumi/src/helm/openunison-kargo/.helmignore | 23 ++ pulumi/src/helm/openunison-kargo/Chart.yaml | 24 +++ .../templates/ingresses/localhost.yaml | 60 ++++++ .../resultgroups/grafana-header.yaml | 12 ++ pulumi/src/helm/openunison-kargo/values.yaml | 0 pulumi/src/ingress_nginx/__init__.py | 0 pulumi/src/ingress_nginx/deploy.py | 104 +++++++++ pulumi/src/kubernetes_dashboard/deploy.py | 132 ++++++++++++ pulumi/src/kv_manager/deploy.py | 3 +- pulumi/src/openunison/deploy.py | 200 ++++++++++-------- 17 files changed, 651 insertions(+), 129 deletions(-) create mode 100644 docs/images/https.png create mode 100644 docs/images/ports.png create mode 100644 docs/images/public.png create mode 100644 pulumi/src/helm/openunison-kargo/.helmignore create mode 100644 pulumi/src/helm/openunison-kargo/Chart.yaml create mode 100644 pulumi/src/helm/openunison-kargo/templates/ingresses/localhost.yaml create mode 100644 pulumi/src/helm/openunison-kargo/templates/resultgroups/grafana-header.yaml create mode 100644 pulumi/src/helm/openunison-kargo/values.yaml create mode 100644 pulumi/src/ingress_nginx/__init__.py create mode 100644 pulumi/src/ingress_nginx/deploy.py diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index efe1358..d2a4817 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -27,7 +27,10 @@ 2222, 6000, 7681, - 8080 + 8080, + 10443, + 11443, + 12443 ], "customizations": { "vscode": { diff --git a/Taskfile.yaml b/Taskfile.yaml index dc61cd1..09f8250 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -15,7 +15,7 @@ vars: talos_patch: "{{.talos_dir}}/patch/cluster.yaml" talos_config_file: "{{.talos_dir}}/manifest/talosconfig" cluster_name: "talos-kargo-docker" - exposed_ports: "30590:30590/tcp" + exposed_ports: "30590:30590/tcp,10443:10443/tcp" memory: "8192" arch: sh: | @@ -138,6 +138,67 @@ tasks: - source .envrc && pulumi config set --path multus.enabled false - source .envrc && pulumi config set --path vm.enabled false + install-gum: + desc: Installs the gum utility for collecting user input + cmds: + - test -e /usr/bin/gum || wget -P /tmp https://github.com/charmbracelet/gum/releases/download/v0.14.5/gum_0.14.5_amd64.deb + - test -e /usr/bin/gum || sudo dpkg -i /tmp/gum_0.14.5_amd64.deb + + install-pen: + desc: Installs the pen utility for setting up port forwarding + cmds: + - |- + if [[ -z "${GITHUB_USER}" ]]; then + echo "Not running in GitHub CodeSpace" + else + echo "Running in GitHub CodeSpace" + test -e /usr/bin/pen || sudo apt-get update + test -e /usr/bin/pen || sudo apt-get install -y pen + fi + + configure-openunison: + desc: "Configure OpenUnison." + + cmds: + - task: install-gum + - task: install-pen + - pen 11443 127.0.0.1:10443 + - pen 12443 127.0.0.1:10443 + - source .envrc && pulumi stack select --create {{.pulumi_stack_identifier}} || true + - source .envrc && pulumi config set --path openunison.enabled true + - source .envrc && pulumi config set --path kubernetes_dashboard.enabled true + - source .envrc && pulumi config set --path openunison.github.client_id $(gum input --placeholder='GitHub OAuth2 Client Id' --header='GitHub OAuth2 Client Id') + - source .envrc && pulumi config set --secret --path openunison.github.client_secret $(gum input --placeholder='GitHub OAuth2 Client Secret' --header='GitHub OAuth2 Client Secret') + - source .envrc && pulumi config set --path openunison.github.teams $(gum input --placeholder='GitHub OAuth2 Teams' --header='GitHub OAuth2 Teams') + - |- + if [[ -z "${GITHUB_USER}" ]]; then + + else + echo "Set your GitHub OAuth2 Application's 'Authorization callback URL' to https://$CODESPACE_NAME-10443.app.github.dev/auth/github" + fi + + enable-kubevirt-manager: + desc: Enables the KubeVirt Manager Web UI + cmds: + - task: install-gum + - task: install-pen + - pen 13443 127.0.0.1:10443 + - source .envrc && pulumi stack select --create {{.pulumi_stack_identifier}} || true + - source .envrc && pulumi config set --path kubevirt_manager.enabled true + + enable-prometheus: + desc: Enables Prometheus + cmds: + - task: install-gum + - task: install-pen + - pen 14443 127.0.0.1:10443 + - pen 15443 127.0.0.1:10443 + - pen 16443 127.0.0.1:10443 + - source .envrc && pulumi stack select --create {{.pulumi_stack_identifier}} || true + - source .envrc && pulumi config set --path prometheus.enabled true + + + iac-deploy: desc: "Deploy Pulumi infrastructure." cmds: diff --git a/docs/OPENUNISON.md b/docs/OPENUNISON.md index deeba42..de0ea57 100644 --- a/docs/OPENUNISON.md +++ b/docs/OPENUNISON.md @@ -2,31 +2,65 @@ # Dependencies -1. Ingress NGINX (not included for now) +1. Ingress NGINX -For MVP Ingress NGINX is required - https://kubernetes.github.io/ingress-nginx/deploy/ +OpenUnison requires the NGINX Ingress controller for MVP. While several controllers are supported, we wanted to keep it simple for now. If you're running Kargo in GitHub CodeSpaces, NGINX will be configured to support port forwarding so you can access OpenUnison, and your cluster, from anywhere on the internet. If running Kargo on bare metal, You'll need to configure Cilium's `LoadBalancer` to support NGINX. -If you don't have a load balancer setup you'll want to deploy as a `DaemonSet` and update the `Deployment` or `DaemonSet` to listen on `hostPort`. First, patch the `ingress-nginx` `Namespace` to allow privileged pods: +2. DNS suffix (Bare Metal Only) -```sh -kubectl patch namespace ingress-nginx -p '{"metadata":{"labels":{"pod-security.kubernetes.io/enforce":"privileged"}}}' +OpenUnison requires a minimum of three host names. More if deploying additional platform management apps. For this reason, you'll need to create a DNS wildcard for a domain suffix to point to your load balancer. For instance, in the below examples a wildcard of \*.kargo.tremolo.dev was setup with an A record for my lab hosts. For a full explination, see - https://openunison.github.io/deployauth/#host-names-and-networking + +3. GitHub Deployment + +Before deploying OpenUnison, you'll need to create an organization on GitHub. This is 100% free. Once you have created an organization, you can setup an OAuth App. See https://openunison.github.io/deployauth/#github for instructions. + +For deployments to GitHub CodeSpaces, enter a fake URL for the redirect for now. When you setup SSO in the code space, you'll be given a URL to use. + +For bare metal, your redirect URL will be `https://k8sou.DNS Suffix/auth/github`. You should also create a Team that you'll use authorizing access to your lab. Keep your `client_id` and `client_secret`. + + +# Setup + +## GitHub CodeSpace + +Once you've run `task deploy`, the next step is to run: + +```bash +task configure-openunison ``` +You'll be asked for: + +1. GitHub OAuth2 Application Client ID +2. GitHub OAuth2 Application Client Secret +3. The name of a GitHub team in the form of org/team. For Instance, `TremoloSecurity/github-demos` + +When the configuration is done, you'll be presented with a redirect URL. Configure your OAuth2 application with this URL as the redirect. -Next, patch the `DaimonSet` / `Deployment` to listen on 80 and 443: +Next, run the deployment again: ```sh -kubectl patch deployments ingress-nginx-controller -n ingress-nginx -p '{"spec":{"template":{"spec":{"containers":[{"name":"controller","ports":[{"containerPort":80,"hostPort":80,"protocol":"TCP"},{"containerPort":443,"hostPort":443,"protocol":"TCP"}]}]}}}}' +task deploy ``` -2. DNS suffix +With the deployment completed, you need to configure three ports to enable HTTPS and public access: -OpenUnison requires a minimum of three host names. More if deploying aditional platform management apps. For this reason, you'll need to create a DNS wildcard for a domain suffix to point to your nodes/load balancer. For instance, in the below examples a wildcard of \*.kargo.tremolo.dev was setup with an A record for my lab hosts. For a full explination, see - https://openunison.github.io/deployauth/#host-names-and-networking +* 10443 +* 11443 +* 12443 -3. GitHub Deployment +For each port, navigate to the ***PORTS*** tab in you VSCode window: -Before deploying OpenUnison, you'll need to create an orgnaization on GitHub. This is 100% free. Once you have created an organization, you can setup an OAuth App. See https://openunison.github.io/deployauth/#github for instructions. Your redirect URL will be `https://k8sou.DNS Suffix/auth/github`. You should also create a Team that you'll use authorizing access to your lab. Keep your `client_id` and `client_secret`. +![Ports Tab](images/ports.png "Ports Tab") -# Setup +Right click on the port, choose ***Change Port Protocol*** and choose ***HTTPS*** + +![HTTPS](images/https.png "HTTPS") + +Finally, mark the port as public by again right clicking on the port, choose ***Port Visibility*** and select ***Public***. + +Repeat this step for all three of the ports 10443,11442, and 12443. + +## Bare Metal Enable Cert-Manager @@ -72,4 +106,20 @@ If you want to allow more users to access your cluster, add them to the team you # Using OpenUnison +## GitHub CodeSpace + +To access your cluster running a CodeSpace, get hte URL for the 10443 port. If everything is configured correctly, you'll be prompted to continue by GitHub and then to trust your GitHub Application. After that, you'll be logged in to OpenUnison with access to your cluster. + +### Limitations + +When running in CodeSpaces, any action that requires SPDY will not work, this includes: + +* kubectl exec +* kubectl cp +* kubectl port-forward + +You can use the terminal for any `Pod` in the Kubernetes Dashboard though. + +## Bare Metal + See our manual - https://openunison.github.io/documentation/login-portal/ diff --git a/docs/images/https.png b/docs/images/https.png new file mode 100644 index 0000000000000000000000000000000000000000..9d77812d8fabfcfbcfe4746e6b57687a50b53934 GIT binary patch literal 407898 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 z zXN1hvr<|IFoY-D=8=~5P9%!U^n`80xHH(FLR?cKz#7N!_EKDAxNEASUoTShSP1h`( zOFG}*IorO}F`ph%^qMF%3YR z0IBnbx`C~L*f_~`vbhUTorm&69E}btvYO3`f7t>WDoeLX1JiOx>cg8Xvp^w3-G>^d zQz>Rv2To9=E?Uj@>AUut;@s^8Y?Oks)$0fuTv-m9qO^3btXo8E8=P?iJ8e6+4ymMD zyv6KZKa?iZ-BD)i5y!<*J);E7qVo2DUi++I*nt`t`BrUix-#p*BTds+QSf#K96&xD zU