diff --git a/.github/workflows/sync-deploy-templates.yml b/.github/workflows/sync-deploy-templates.yml new file mode 100644 index 000000000..da40f0123 --- /dev/null +++ b/.github/workflows/sync-deploy-templates.yml @@ -0,0 +1,34 @@ +name: Sync deploy templates to S3 + +on: + push: + branches: [main] + paths: + - "templates/reverse-proxy/**" + +permissions: + id-token: write + contents: read + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.DEPLOY_TEMPLATES_ROLE_ARN }} + aws-region: eu-central-1 + + - name: Validate CloudFormation template + run: | + aws cloudformation validate-template \ + --template-body file://templates/reverse-proxy/netbird-proxy-cfn.yaml + + - name: Upload CloudFormation template + run: | + aws s3 cp templates/reverse-proxy/netbird-proxy-cfn.yaml \ + s3://netbird-deploy-templates/templates/netbird-proxy-cfn.yaml diff --git a/.github/workflows/test-cloud-deploy.yml b/.github/workflows/test-cloud-deploy.yml new file mode 100644 index 000000000..dce7b461a --- /dev/null +++ b/.github/workflows/test-cloud-deploy.yml @@ -0,0 +1,78 @@ +name: Test cloud deploy config + +on: + pull_request: + paths: + - "docker/init_react_envs.sh" + - "templates/reverse-proxy/**" + - "src/modules/reverse-proxy/clusters/ClusterCloudDeploy.tsx" + - ".github/workflows/test-cloud-deploy.yml" + +permissions: + contents: read + +jobs: + csp-connect-src: + name: CSP allows cloud provider APIs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install nginx + run: | + sudo apt-get update + sudo apt-get install -y nginx gettext-base + + - name: Prepare nginx layout expected by the init script + run: | + sudo mkdir -p /etc/nginx/http.d /usr/share/nginx/html + echo 'add_header Content-Security-Policy "placeholder" always;' | sudo tee /etc/nginx/http.d/default.conf + sudo touch /usr/share/nginx/html/OidcTrustedDomains.js.tmpl + sudo systemctl start nginx + + - name: Run init script with production-like env + env: + AUTH_AUTHORITY: https://auth.example.com + AUTH_CLIENT_ID: test-client + AUTH_AUDIENCE: test-audience + AUTH_SUPPORTED_SCOPES: openid profile email + USE_AUTH0: "false" + NETBIRD_MGMT_API_ENDPOINT: https://api.example.com + run: sudo -E bash docker/init_react_envs.sh + + - name: Assert provider APIs are in connect-src + run: | + CSP=$(grep -o 'Content-Security-Policy "[^"]*"' /etc/nginx/http.d/default.conf) + echo "Generated CSP: $CSP" + CONNECT_SRC=$(echo "$CSP" | sed 's/.*connect-src \([^;]*\);.*/\1/') + echo "connect-src: $CONNECT_SRC" + status=0 + for origin in https://api.hetzner.cloud https://api.digitalocean.com; do + if echo "$CONNECT_SRC" | grep -qF "$origin"; then + echo "OK: $origin" + else + echo "MISSING in connect-src: $origin" + status=1 + fi + done + exit $status + + cfn-template-url: + name: CloudFormation template URL is live + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Extract template URL from component and check it + run: | + URL=$(grep -o 'https://[^"]*netbird-proxy-cfn\.yaml' src/modules/reverse-proxy/clusters/ClusterCloudDeploy.tsx) + echo "CFN_TEMPLATE_URL: $URL" + test -n "$URL" + # Non-blocking: the template is published by sync-deploy-templates on + # the default branch, so it may not exist yet for a PR that only edits + # the URL. Warn instead of failing the check. + if curl -sfI "$URL" >/dev/null; then + echo "OK: template URL is live" + else + echo "::warning::CloudFormation template URL is not reachable yet: $URL" + fi diff --git a/docker/init_react_envs.sh b/docker/init_react_envs.sh index 3d4a70863..75e26da7c 100644 --- a/docker/init_react_envs.sh +++ b/docker/init_react_envs.sh @@ -80,7 +80,7 @@ echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}" FIRST_PARTY_CSP="pkgs.netbird.io" FIRST_PARTY_CSP_CONNECT_SRC="wss://*.netbird.io" THIRD_PARTY_CSP="*.licdn.com *.linkedin.com *.vector.co *.sibforms.com *.hotjar.com *.hotjar.io *.redditstatic.com pixel-config.reddit.com *.clarity.ms c.bing.com *.microsoft.com googleads.g.doubleclick.net pagead2.googlesyndication.com www.google.com www.googleadservices.com *.google-analytics.com *.googletagmanager.com analytics.google.com *.hubapi.com *.hs-banner.com *.hubspot.com *.hubspot.net js.hs-analytics.com *.hsforms.net *.hscollectedforms.net *.hs-analytics.net *.hsforms.com track.hubspot.com *.hsadspixel.net static.hsappstatic.net" -THIRD_PARTY_CSP_CONNECT_SRC="https://api.github.com/repos/netbirdio/netbird/releases/latest https://raw.githubusercontent.com/netbirdio/dashboard/ wss://ws.hotjar.com" +THIRD_PARTY_CSP_CONNECT_SRC="https://api.github.com/repos/netbirdio/netbird/releases/latest https://raw.githubusercontent.com/netbirdio/dashboard/ wss://ws.hotjar.com https://api.hetzner.cloud https://api.digitalocean.com" THIRD_PARTY_CSP_SCRIPT_SRC="'sha256-7knV6EIjKUvCpYWE2rCYx8dYV2WCNb2bpTuitFXzBcA=' *.hs-scripts.com" CSP_DOMAINS="" diff --git a/src/app/(dashboard)/reverse-proxy/clusters/page.tsx b/src/app/(dashboard)/reverse-proxy/clusters/page.tsx index f6582726d..ef15f9c79 100644 --- a/src/app/(dashboard)/reverse-proxy/clusters/page.tsx +++ b/src/app/(dashboard)/reverse-proxy/clusters/page.tsx @@ -40,9 +40,9 @@ export default function ReverseProxyClustersPage() {
+ {rootPassword}
+
+
+
+ {isGeneratingToken ? "Generating proxy token..." : token}
+
+
+
- {isGeneratingToken && (
-
-
- Generating proxy token...
-
- )}
-
- {renderHighlightedCommand(deployment.command, [
- managementUrl,
- domain,
- tokenValue,
- ])}
-
-
-
+ {isGeneratingToken && (
+
+
+ Generating proxy token...
+
+ )}
+
+ {renderHighlightedCommand(deployment.command, [
+ managementUrl,
+ domain,
+ tokenValue,
+ ])}
+
+
+