Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend): Support running behind a corporate proxy [RHIDP-2217] #1225

Conversation

rm3l
Copy link
Member

@rm3l rm3l commented May 3, 2024

Description

This PR allows running the Showcase app behind a corporate proxy, which was the root cause of a login failure using the GitHub auth behind a proxy.

It does so per the upstream instructions provided on this page: https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md
This way, it can honor the conventional HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables (and their lowercase equivalents).

The undici and global-agent packages added here allow covering settings for the native fetch and node-fetch respectively. Note that even if node-fetch is recommended for HTTP data fetching by Backstage packages [ADR013], we identified a couple of plugins making use of other libraries like Axios (like the Keycloak backend plugin - see RHIDP-2217 for the full list). Axios reportedly already honors the proxy environment variables above [doc].
I tested the Keycloak backend plugin as an example to ensure this.

Which issue(s) does this PR fix

PR acceptance criteria

Please make sure that the following steps are complete:

  • GitHub Actions are completed and successful
  • Unit Tests are updated and passing
  • E2E Tests are updated and passing
  • Documentation is updated if necessary (requirement for new features)
  • Add a screenshot if the change is UX/UI related

How to test changes / Special notes to the reviewer

Local Development

You can run locally with yarn:

  1. First start a proxy server - example with a Squid image:
podman container run --rm --name squid-container -e TZ=UTC -p 3128:3128 -it docker.io/ubuntu/squid:latest 
  1. In a separate terminal, start the application with the proxy environment variables.
GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE='' \
  HTTP_PROXY=http://localhost:3128 \
  HTTPS_PROXY=http://localhost:3128 \
  NO_PROXY='localhost,example.org' \
  yarn start
  1. Inspect the proxy logs and you should see that requests are sent through the proxy, e.g.:
1715067448.970    185 10.42.0.19 TCP_TUNNEL/200 5171 CONNECT raw.githubusercontent.com:443 - HIER_DIRECT/185.199.111.133 -
1715067450.517    256 10.42.0.19 TCP_TUNNEL/200 5129 CONNECT raw.githubusercontent.com:443 - HIER_DIRECT/185.199.111.133 -

Full test

For a more complete test, the most challenging part of testing the changes here is to set up an environment where an application is forbidden access to the public Internet except through a given proxy.
We can simulate such an environment in a Kubernetes namespace with the help of Network Policies to control ingress/egress traffic.
For example:

  1. Make sure the network plugin in your Kubernetes cluster supports network policies. I created a cluster with k3d (k3d cluster create), and it supports Network Policies out of the box.

  2. Create a separate proxy namespace, and deploy a Squid-based proxy application there:

kubectl create namespace proxy

cat <<EOF | kubectl -n proxy apply -f -
apiVersion: v1
kind: Service
metadata:
  name: squid-service
  namespace: proxy
  labels:
    app: squid
spec:
  ports:
  - port: 3128
  selector:
    app: squid

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: squid-deployment
  namespace: proxy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: "squid"
  template:
    metadata:
      labels:
        app: squid
    spec:
      containers:
      - name: squid
        image: docker.io/ubuntu/squid:latest
        ports:
        - containerPort: 3128
          name: squid
          protocol: TCP
EOF
  1. Create the namespace where the Showcase application will be running
kubectl create namespace my-ns
  1. Add the network policies in the namespace above. The first one denies all egress traffic except to the DNS resolver and the Squid proxy. The second one allows ingress and egress traffic in the same namespace, because the Showcase app pod needs to contact the local Database pod.
cat <<EOF | kubectl -n my-ns apply -f -
---
# Deny all egress traffic in this namespace => proxy settings can be used to overcome this.
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: default-deny-egress-with-exceptions
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  # allow DNS resolution (we need this allowed, otherwise we won't be able to resolve the DNS name of the Squid proxy service)
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
      - port: 53
        protocol: UDP
      - port: 53
        protocol: TCP
  # allow traffic to Squid proxy
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: proxy
    ports:
    - port: 3128
      protocol: TCP

---
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-same-namespace
spec:
  podSelector: {}
  ingress:
  - from:
    - podSelector: {}
  egress:
  - to:
    - podSelector: {}
EOF
  1. Deploy the showcase application using the image from this PR (quay.io/janus-idp/backstage-showcase:pr-1225). I tested this using the RHDH Operator, but it should work with the Helm Chart as well. For example, to only test the GitHub login issue:
    a. Follow the instructions to create a GitHub app
    b. Make sure to use the image from this PR (spec.application.image field if using the Operator).
    c. GitHub login should fail unless the HTTP(S)_PROXY environment variables are set, like so:
# Make sure to create the appropriate ConfigMaps and Secrets
apiVersion: rhdh.redhat.com/v1alpha1
kind: Backstage
metadata:
  name: my-rhdh
spec:
  application:
    image: quay.io/janus-idp/backstage-showcase:pr-1225
    appConfig:
      configMaps:
        - name: app-config-rhdh
    dynamicPluginsConfigMapName: dynamic-plugins-rhdh
    extraEnvs:
      envs:
        - name: HTTP_PROXY
          value: 'http://squid-service.proxy.svc.cluster.local:3128'
        - name: HTTPS_PROXY
          value: 'http://squid-service.proxy.svc.cluster.local:3128'
        - name: NO_PROXY
          value: 'localhost'
        - name: ROARR_LOG
          # Logs from global-agent (to inspect proxy settings)
          value: 'true'
      secrets:
        - name: secrets-rhdh

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-rhdh
data:
  "app-config-rhdh-auth.yaml": |
    auth:
      environment: development
      session:
        secret: my-super-secret-secret
      providers:
        github:
          development:
            clientId: '${GH_CLIENT_ID}'
            clientSecret: '${GH_CLIENT_SECRET}'

  "app-config-rhdh-catalog.yaml": |
    catalog:
      import:
        entityFilename: catalog-info.yaml
        pullRequestBranchName: backstage-integration
      rules:
        - allow: [Component, System, Group, Resource, Location, Template, API]
      locations:
        # Note: integrations.github[].apps must be correctly configured to read GitHub locations
        - type: url
          target: https://github.com/janus-idp/backstage-showcase/blob/main/catalog-entities/all.yaml

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: dynamic-plugins-rhdh
data:
  dynamic-plugins.yaml: |
    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic'
        disabled: false
        pluginConfig:
          catalog:
            providers:
              github:
                myorg:
                  organization: '${GH_ORG}'
                  schedule:
                    # supports cron, ISO duration, "human duration" (used below)
                    frequency: { minutes: 30}
                    # supports ISO duration, "human duration (used below)
                    timeout: { minutes: 3}
                    initialDelay: { seconds: 15}

---
apiVersion: v1
kind: Secret
metadata:
  name: secrets-rhdh
stringData:
  # generated with the command below (from https://backstage.io/docs/auth/service-to-service-auth/#setup):
  # node -p 'require("crypto").randomBytes(24).toString("base64")'
  BACKEND_SECRET: "R2FxRVNrcmwzYzhhN3l0V1VRcnQ3L1pLT09WaVhDNUEK" # notsecret
  GH_ORG: "my-gh-org"
  GH_CLIENT_ID: "changeme"
  GH_CLIENT_SECRET: "changeme"

Copy link

openshift-ci bot commented May 3, 2024

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@rm3l rm3l force-pushed the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch from e85e296 to 1eb2003 Compare May 3, 2024 11:58
Copy link
Contributor

github-actions bot commented May 3, 2024

The image is available at: quay.io/janus-idp/backstage-showcase:pr-1225!

@rm3l rm3l force-pushed the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch from 1eb2003 to 3d6bec8 Compare May 6, 2024 09:06
Copy link
Contributor

github-actions bot commented May 6, 2024

The image is available at: quay.io/janus-idp/backstage-showcase:pr-1225!

@rm3l rm3l force-pushed the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch from 3d6bec8 to 5f2c044 Compare May 7, 2024 09:24
Copy link
Contributor

github-actions bot commented May 7, 2024

The image is available at: quay.io/janus-idp/backstage-showcase:pr-1225!

@rm3l rm3l force-pushed the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch from 5f2c044 to e9457bc Compare May 7, 2024 11:24
Copy link
Contributor

github-actions bot commented May 7, 2024

The image is available at: quay.io/janus-idp/backstage-showcase:pr-1225!

@rm3l rm3l force-pushed the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch from e9457bc to 57c4990 Compare May 7, 2024 14:24
Copy link
Contributor

github-actions bot commented May 7, 2024

The image is available at: quay.io/janus-idp/backstage-showcase:pr-1225!

@rm3l rm3l changed the title [WIP] feat: Support running behind a corporate proxy [RHIDP-2217] feat(backend): Support running behind a corporate proxy [RHIDP-2217] May 7, 2024
@rm3l rm3l marked this pull request as ready for review May 7, 2024 15:17
@rm3l rm3l requested a review from a team as a code owner May 7, 2024 15:17
@rm3l rm3l requested a review from kadel May 8, 2024 08:18
Copy link

@gazarenkov gazarenkov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any tests expected?

@rm3l
Copy link
Member Author

rm3l commented May 13, 2024

Any tests expected?

This will make sense as E2E tests, which are going to be covered in https://issues.redhat.com/browse/RHIDP-1955.

@rm3l rm3l force-pushed the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch from 57c4990 to 27b84b9 Compare May 13, 2024 11:57
@rm3l rm3l requested a review from gazarenkov May 13, 2024 11:58
Copy link
Contributor

The image is available at: quay.io/janus-idp/backstage-showcase:pr-1225!

@coreydaley
Copy link
Member

@rm3l I think that the Local development and Full Test instructions that you wrote in the description for this pull request would be a great addition to a docs/proxy.md file as part of this pull request.

rm3l and others added 12 commits May 21, 2024 11:13
Command used for reference: 'yarn add --dev @types/global-agent'

Otherwise, we get the following errors when building the container
images:

//:tsc: cache miss, executing 7cdd96a5dd9f08b5
//:tsc: $ tsc
//:tsc: packages/backend/src/index.ts:20:27 - error TS7016: Could not
find a declaration file for module 'global-agent'.
'/opt/app-root/src/node_modules/global-agent/dist/index.js' implicitly
//:tsc:   Try `npm i --save-dev @types/global-agent` if it exists or add
a new declaration (.d.ts) file containing `declare module
'global-agent';`
//:tsc:
//:tsc:                              ~~~~~~~~~~~~~~
//:tsc:
//:tsc:
//:tsc: Found 1 error in packages/backend/src/index.ts:20
//:tsc:
//:tsc: error Command failed with exit code 1.
//:tsc: info Visit https://yarnpkg.com/en/docs/cli/run for documentation
about this command.
//:tsc: ERROR: command finished with error: command (/opt/app-root/src/)
/tmp/yarn--1714731744742-0.9188035523240228/yarn run tsc exited (1)
//#tsc: command (/opt/app-root/src/)
/tmp/yarn--1714731744742-0.9188035523240228/yarn run tsc exited (1)
…he container image

Setting it to an empty value allows global-agent to rely on the rather
conventional HTTP(S)_PROXY and NO_PROXY env vars. [1]
Otherwise, users would need to configure both GLOBAL_AGENT_HTTP(S)_PROXY
and HTTP(S)_PROXY to make proxying work with both global-agent and other
libs.
Also, it might be a bit confusing for the user to have to set it explicitly
to an empty value.
We can set it the other way around, but users can still override it if
needed.

[1] https://github.com/gajus/global-agent#what-is-the-reason-global-agentbootstrap-does-not-use-http_proxy
This would simplify the merging process in case of upstream changes

Co-authored-by: Gennady Azarenkov <gazarenkov@redhat.com>
…fault config

Co-authored-by: Gennady Azarenkov <gazarenkov@redhat.com>
…s/proxy.md' file

Co-authored-by: Corey Daley <cdaley@redhat.com>
…e supported libraries for HTTP data fetching

Co-authored-by: Kim Tsao <ktsao@redhat.com>
Co-authored-by: Corey Daley <cdaley@redhat.com>
@rm3l rm3l force-pushed the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch from 0c7c9be to 37ae9ed Compare May 21, 2024 09:17
Copy link

sonarcloud bot commented May 21, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.1% Duplication on New Code

See analysis details on SonarCloud

@rm3l
Copy link
Member Author

rm3l commented May 21, 2024

Rebased and force-pushed to fix a conflict with the following files:

  • .rhdh/docker/Dockerfile
  • docker/Dockerfile

@rm3l
Copy link
Member Author

rm3l commented May 21, 2024

/cc @gashcrumb

@openshift-ci openshift-ci bot requested a review from gashcrumb May 21, 2024 09:39
Copy link
Contributor

The image is available at: quay.io/janus-idp/backstage-showcase:pr-1225!

@rm3l
Copy link
Member Author

rm3l commented May 21, 2024

/test e2e-tests

@kim-tsao
Copy link
Member

/approve

@kim-tsao
Copy link
Member

/lgtm

Copy link

openshift-ci bot commented May 21, 2024

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: kim-tsao

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot openshift-merge-bot bot merged commit 4cf349c into janus-idp:main May 21, 2024
8 checks passed
@rm3l rm3l deleted the RHIDP-2217--add-corporate-proxy-support-to-rhdh branch May 21, 2024 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants