Skip to content

Latest commit

 

History

History
922 lines (662 loc) · 27.9 KB

2024.05.rhdp.prod.md

File metadata and controls

922 lines (662 loc) · 27.9 KB

redhat developer hub

Customer want to integrate Azure DevOps with Red Hat Developer Hub, so that they can see the code, and the pipeline status in the Developer Hub. We will try to do that.

The whole senario includes:

  1. rhdh
  2. dev workspace
  3. ocp gitops

To complish the target, we will use several components:

  1. rhsso, for azure ad integration.
  2. backstage plugin
    1. azure devops (included in rhdh)
    2. azure devops auto discovery (working)
    3. msgraph(does not work right now)

There is a great demo in demo.redhat.com, we will try this lab based on that demo env.

deploy using demo.redhat.com

try with demo.redhat.com instance:

  • Red Hat Developer Hub Demo
    • using the 'latest' version
      • RHDH Version: 1.2.0
      • Backstage Version: 1.26.5
      • Upstream: janus-idp/backstage-showcase main @ e3654a5e
      • Midstream: gitlab.cee.redhat.com/rhidp/rhdh rhdh-1-rhel-9 @ cd137ad6

The document of this demo is here.

The github repo used for integrated gitlab:

rhdh azure devops plugin

After the demo env startup, we need to customize the backstage plugin, to enable the azure devops plugin.

Azure DevOps Env

Before we can setup the plugin in rhdh, we need to setup the azure devops env.

create azure devops service in :

create a personal access token:

Try to create the personal access token in all organization, this will elimate the permission issue.

Install Code Search Feature for Azure devops

create a repo under your organization, and project. The content of the repo does matter for this lab, because it contains catalog for demo system, components, and api.

Find your tenant id, client id, and client secret

Create an application, then you can get the client id

Set correct permission

Set searchable branch.

rhdh app config

In this lab, RHDP is gitopts installed, so find in gitlab, and change the content, both plugins and integrations.

Apply below content to the backstage-values.yaml, do not delete existed, just add. Not all config is correct, I am still working on it. Replace the secure key with your own ones.

Tip

get checksum with npm info

data:
  dynamic-plugins.yaml: |
    includes:
    - dynamic-plugins.default.yaml
    plugins:
      - disabled: false
        package: ./dynamic-plugins/dist/backstage-plugin-azure-devops
      - disabled: false
        package: ./dynamic-plugins/dist/backstage-plugin-azure-devops-backend-dynamic
      # - disabled: false
      #   package: ./dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-azure-dynamic
      # - disabled: false
      #   integrity: >-
      #       sha512-WxRXsTppHKxzMHpUvEiQR3rYPypSHDHABAqegjareHYEXgA5uVBsRW2zES6GpOeei45KnxGL+NcuoKQezg1D7A==
      #   package: '@backstage/[email protected]'
      # - disabled: false
      #   integrity: >-
      #       sha512-wHZC7riqyakSzPrxM1+edu1Et99Q0gAd0WXxrnclUo7lT45+xvqYxzbdVR9Kr7OHr/6AugMghJZV1BzCxl2+PQ==
      #   package: '@backstage/[email protected]'
      - disabled: false
        integrity: >-
            sha512-H3d4UThnU+EUCFfH3lBPvm0mYXdAQ/GG4blg71Oe8nfjm9eN9yATxq8r74430Xyi1xn+2HVbVbLyvWpgpIp/ig==
        package: '@backstage/[email protected]'
      - disabled: false
        integrity: >-
            sha512-C7qhlHOQeXMNMPekgEoTdTiVq2hHdZkHvUHpb4EyCOE8MzGFx1LTl7r7ch4jiFkr15YQuqOImYUc/JhGNnes8A==
        package: '@backstage/[email protected]'
      # - disabled: false
      #   integrity: >-
      #       sha512-eBfl2rPN3HrgECEeHS9uw9Y4xaAQgzNu7qn/kYarqTRi3Rnn5V8zMm5jU4gcqfcxdBbdpUb9HpRvOqk9V96VSA==
      #   package: '@backstage/[email protected]'

upstream:
  backstage:

    extraEnvVars:
      - name: AZURE_CLIENT_ID
        value: <change me to secret value>
      - name: AZURE_CLIENT_SECRET
        value: <change me to secret value>
      - name: AZURE_TENANT_ID
        value: <change me to secret value>
      - name: AZURE_TOKEN
        value: <change me to secret value>
      - name: AZURE_ORG
        value: wangzheng422
      - name: KEYCLOAK_BASE_URL
        value: https://keycloak-backstage.apps.cluster-wzjhs.sandbox2376.opentlc.com/auth
      - name: KEYCLOAK_LOGIN_REALM
        value: backstage
      - name: KEYCLOAK_REALM
        value: backstage
      - name: KEYCLOAK_CLIENT_ID
        valueFrom:
          secretKeyRef:
            key: CLIENT_ID
            name: keycloak-client-secret-backstage
      - name: KEYCLOAK_CLIENT_SECRET
        valueFrom:
          secretKeyRef:
            key: CLIENT_SECRET
            name: keycloak-client-secret-backstage

    appConfig:
      integrations:
        azure:
          - host: dev.azure.com
            credentials:
              - organizations:
                  - ${AZURE_ORG}
                personalAccessToken: ${AZURE_TOKEN}
                
      catalog:
        locations:
          - target: https://dev.azure.com/wangzheng422/demo/_git/service-demo?path=%2Forg.yaml&version=GBmain&_a=contents
            # can be git url from azure devops repo
            # target: https://dev.azure.com/wangzheng422/demo/_git/service-demo?path=%2Forg.yaml&version=GBmain&_a=contents
            # https://github.com/wangzheng422/backstage-customize/blob/data/org.yaml
            type: url
            rules:
              - allow: [Group, User]
          - target: https://github.com/redhat-developer/red-hat-developer-hub-software-templates/blob/main/templates/azure/dotnet-frontend/template.yaml
            type: url
            rules:
              - allow: [Template]
              S
        providers:
          azureDevOps:
            yourProviderId: # identifies your dataset / provider independent of config changes
              organization: wangzheng422
              project: '*'
              repository: '*' # this will match all repos starting with service-*
              path: /catalog-info.yaml
              schedule: # optional; same options as in TaskScheduleDefinition
                # supports cron, ISO duration, "human duration" as used in code
                frequency: { minutes: 30 }
                # supports ISO duration, "human duration" as used in code
                timeout: { minutes: 3 }
          microsoftGraphOrg:
            default:
              tenantId: ${AZURE_TENANT_ID}
              clientId: ${AZURE_CLIENT_ID}
              clientSecret: ${AZURE_CLIENT_SECRET}
              user:
                filter: accountEnabled eq true and userType eq 'member'
                select: [id,mail,displayName,givenName,mobilePhone]
              group:
                filter: >
                  securityEnabled eq false
                  and mailEnabled eq true
                  and groupTypes/any(c:c+eq+'Unified')
              schedule:
                frequency: PT1H
                timeout: PT50M
          keycloakOrg:
            default:
              baseUrl: ${KEYCLOAK_BASE_URL}
              loginRealm: ${KEYCLOAK_LOGIN_REALM}
              realm: ${KEYCLOAK_REALM}
              clientId: ${KEYCLOAK_CLIENT_ID}
              clientSecret: ${KEYCLOAK_CLIENT_SECRET}
              schedule: # optional; same options as in TaskScheduleDefinition
                # supports cron, ISO duration, "human duration" as used in code
                frequency: { minutes: 1 }
                # supports ISO duration, "human duration" as used in code
                timeout: { minutes: 1 }
                initialDelay: { seconds: 15 }


      enabled:
        azure: true
        azureDevOps: true
        microsoftGraphOrg: false
        keycloakOrg: true
        microsoft: false

In gitlab webconsole, change the content and commit

Then, from gitops operator view, update backstage.app.valueFile to the commited raw file url.

Wait sometime, you can see the plugin is enable in RHDP

see the azure devops result

Import the resources, with reference to azure devops, with the auto discovery you can see the components, system, and api.

For API

from the detail view, you can see the dependency relationship.

and you can see the azure devops repo's pull request

and the pipeline status

and the source code.

For components

For system

Because the msgraph does not work right now, you can see new group created, without user and the desire groups.

For users, we can only see the user from git source code.

Here is the catalog-info.yaml, for your referece

---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-system
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
  name: azure-examples
  annotations:
    dev.azure.com/project-repo: demo/service-demo
    dev.azure.com/host-org: dev.azure.com/wangzheng422
spec:
  owner: azure-guests
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: azure-example-website
  annotations:
    dev.azure.com/project-repo: demo/service-demo
    dev.azure.com/host-org: dev.azure.com/wangzheng422
spec:
  type: azure-website
  lifecycle: experimental
  owner: azure-guests
  system: azure-examples
  providesApis: [azure-example-grpc-api]
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-api
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
  name: azure-example-grpc-api
  annotations:
    dev.azure.com/project-repo: demo/service-demo
    dev.azure.com/host-org: dev.azure.com/wangzheng422
spec:
  type: grpc
  lifecycle: experimental
  owner: azure-guests
  system: azure-examples
  definition: |
    syntax = "proto3";

    service Exampler {
      rpc Example (ExampleMessage) returns (ExampleMessage) {};
    }

    message ExampleMessage {
      string example = 1;
    };

Here is the org.yaml, for your reference

---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-user
apiVersion: backstage.io/v1alpha1
kind: User
metadata:
  name: azure-guest
spec:
  memberOf: [azure-guests]
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-group
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
  name: azure-guests
spec:
  type: team
  children: []

disable auto discovery

It seems, you can disable azure devops auto discovery, and add the resource from github manually. The source code just the same.

We will use a repo host on github right now. The demo repo is here:

And you can see the result

And you can see there is already a merge request existed in the azure devops repo.

Azure sso using rhsso/keycloak

The demo.redhat.com 's demo lab, using rhsso with rhdp as the identity provider, so we can use the same way to integrate with azure ad. You can use this method, if the org import(plugin msgraph) from azure do not work.

reference:

setup

Register a new app

Here you can see the new client id,

Create secret for the app

Set the expired date.

Set permission to read user info.

Add additional information to token claim, espeically the groups.

Get endpoint information:

Config rhsso

add azure ad sso integration

Give it a name.

Copy the endpoint config from azure

Get group name and group id from azure entra

Add group to keycloak/rhsso manually, we do not know how to add it automatically.

Add group mapper, so the new user will be added to its group by matching the group id.

Add username mapping to oid, the rhdh will not create user entity for email address format

Get the redirect url setting from rhsso.

Add the redirect url to azure

Easy the security setting for your azure org, we are testing env, so the user can login only with password.

try it out

Open rhdh url, it will redirect to rhsso, select Azure

Login with azure account in your org.

After login, you will be redirected to rhdh, your user info is automaticalty set, because we defined a client scope and mapping for you.

Wait some moments, after rhdh sync user and group info from rhsso/keycloak, you can see the new user created, and link to sso user info.

If you login using an azure user without a group, you will see this:

Azure sso with hacked msgraph

The msgraph plugin does not work with azure/microsoft sso right now, the msgraph will import user with azure email as rhdh username, but azure/microsoft sso will use azure user oid as rhdh username, they are not match, so we need to hack it.

The upstream backstage have ways to match the user using azure oid, but we are rhdh, we can not cusomize the backstage plugin, so we need to hack the msgraph plugin.

We hack the msgraph using this repo. The change is simple, just use azure user oid as rhdh username.

The patch for demo.redhat.com is here:

data:
  dynamic-plugins.yaml: |
    plugins:
      - disabled: false
        package: ./dynamic-plugins/dist/backstage-plugin-azure-devops
      - disabled: false
        package: ./dynamic-plugins/dist/backstage-plugin-azure-devops-backend-dynamic
      # - disabled: false
      #   package: ./dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-azure-dynamic
      # - disabled: false
      #   integrity: >-
      #       sha512-WxRXsTppHKxzMHpUvEiQR3rYPypSHDHABAqegjareHYEXgA5uVBsRW2zES6GpOeei45KnxGL+NcuoKQezg1D7A==
      #   package: '@backstage/[email protected]'
      # - disabled: false
      #   integrity: >-
      #       sha512-wHZC7riqyakSzPrxM1+edu1Et99Q0gAd0WXxrnclUo7lT45+xvqYxzbdVR9Kr7OHr/6AugMghJZV1BzCxl2+PQ==
      #   package: '@backstage/[email protected]'
      - disabled: false
        integrity: >-
            sha512-H3d4UThnU+EUCFfH3lBPvm0mYXdAQ/GG4blg71Oe8nfjm9eN9yATxq8r74430Xyi1xn+2HVbVbLyvWpgpIp/ig==
        package: '@backstage/[email protected]'
      - disabled: false
        integrity: >-
            sha512-RTOzk+k0XCu0ivqqHrnis4lzsQqAhEVv++6bb4exqhU8LpWGX0R15RPljVzHtWKqT35CXhNt0JWYv8hSjUPzgg==
        package: '@wangzheng422/[email protected]'
      # - disabled: false
      #   integrity: >-
      #       sha512-C7qhlHOQeXMNMPekgEoTdTiVq2hHdZkHvUHpb4EyCOE8MzGFx1LTl7r7ch4jiFkr15YQuqOImYUc/JhGNnes8A==
      #   package: '@backstage/[email protected]'
      # - disabled: false
      #   integrity: >-
      #       sha512-eBfl2rPN3HrgECEeHS9uw9Y4xaAQgzNu7qn/kYarqTRi3Rnn5V8zMm5jU4gcqfcxdBbdpUb9HpRvOqk9V96VSA==
      #   package: '@backstage/[email protected]'
      # - disabled: false
      #   integrity: >-
      #       sha512-iRxCHis0E2CemuEQ/CQvk9O5vVw3dRA/EOLvo4Ms1scfFDdJqogHH+KiVzEOf5nhf3YUmPpMT0cB+G4kx+th9A==
      #   package: '@backstage/[email protected]'

upstream:
  backstage:
    # image:
    #   registry: quay.io
    #   repository: wangzheng422/qimgs
    #   tag: 'rhdh-hub-rhel9-1.1-2024.05.17.v02'

    extraEnvVars:
      - name: AZURE_CLIENT_ID
        value: <change me to secret value>
      - name: AZURE_CLIENT_SECRET
        value: <change me to secret value>
      - name: AZURE_TENANT_ID
        value: <change me to secret value>
      - name: AZURE_TOKEN
        value: <change me to secret value>
      - name: AZURE_ORG
        value: wangzheng422
      # - name: KEYCLOAK_BASE_URL
      #   value: https://keycloak-backstage.apps.cluster-qjwdr.sandbox928.opentlc.com/auth
      - name: KEYCLOAK_BASE_URL
        value: $(APP_CONFIG_catalog_providers_keycloakOrg_default_baseUrl)
      - name: KEYCLOAK_LOGIN_REALM
        value: backstage
      - name: KEYCLOAK_REALM
        value: backstage
      - name: KEYCLOAK_CLIENT_ID
        valueFrom:
          secretKeyRef:
            key: CLIENT_ID
            name: keycloak-client-secret-backstage
      - name: KEYCLOAK_CLIENT_SECRET
        valueFrom:
          secretKeyRef:
            key: CLIENT_SECRET
            name: keycloak-client-secret-backstage

    appConfig:
      integrations:
        azure:
          - host: dev.azure.com
            credentials:
              - organizations:
                  - ${AZURE_ORG}
                personalAccessToken: ${AZURE_TOKEN}
                # clientId: ${AZURE_CLIENT_ID}
                # clientSecret: ${AZURE_CLIENT_SECRET}
                # tenantId: ${AZURE_TENANT_ID}


      auth:
        environment: production
        providers:
          microsoft:
            production:
              clientId: ${AZURE_CLIENT_ID}
              clientSecret: ${AZURE_CLIENT_SECRET}
              tenantId: ${AZURE_TENANT_ID}
              domainHint: ${AZURE_TENANT_ID}
              additionalScopes:
                - Mail.Send
              signIn:
                resolvers:
                  # typically you would pick one of these
                  - resolver: idMatchingUserEntityAnnotation
                  - resolver: emailMatchingUserEntityProfileEmail
                  - resolver: emailLocalPartMatchingUserEntityName
                  - resolver: emailMatchingUserEntityAnnotation  

      signInPage: microsoft


      catalog:
        locations:
          # https://dev.azure.com/wangzheng422/demo/_git/service-demo?path=%2Forg.yaml&version=GBmain&_a=contents
          # https://github.com/wangzheng422/backstage-customize/blob/data/org.yaml
          - target: https://dev.azure.com/wangzheng422/demo/_git/service-demo?path=%2Forg.yaml&version=GBmain&_a=contents
            type: url
            rules:
              - allow: [Group, User]
          - target: https://github.com/wangzheng422/red-hat-developer-hub-software-templates/blob/wzh-hack/templates/azure/dotnet-frontend/template.yaml
            type: url
            rules:
              - allow: [Template]

        providers:
          azureDevOps:
            yourProviderId: # identifies your dataset / provider independent of config changes
              organization: wangzheng422
              project: '*'
              repository: '*' # this will match all repos starting with service-*
              path: /catalog-info.yaml
              schedule: # optional; same options as in TaskScheduleDefinition
                # supports cron, ISO duration, "human duration" as used in code
                frequency: { minutes: 30 }
                # supports ISO duration, "human duration" as used in code
                timeout: { minutes: 3 }
          microsoftGraphOrg:
            default:
              tenantId: ${AZURE_TENANT_ID}
              clientId: ${AZURE_CLIENT_ID}
              clientSecret: ${AZURE_CLIENT_SECRET}
              user:
                filter: >
                  accountEnabled eq true and userType eq 'member'
                # select: ['id', 'displayName', 'mail']
              # userPrincipalName eq '[email protected]'
              group:
                filter: >
                  displayName eq 'demo-group-backstage'
              schedule:
                frequency: PT1H
                timeout: PT50M
          keycloakOrg:
            default:
              baseUrl: ${KEYCLOAK_BASE_URL}
              loginRealm: ${KEYCLOAK_LOGIN_REALM}
              realm: ${KEYCLOAK_REALM}
              clientId: ${KEYCLOAK_CLIENT_ID}
              clientSecret: ${KEYCLOAK_CLIENT_SECRET}
              schedule: # optional; same options as in TaskScheduleDefinition
                # supports cron, ISO duration, "human duration" as used in code
                frequency: { minutes: 1 }
                # supports ISO duration, "human duration" as used in code
                timeout: { minutes: 1 }
                initialDelay: { seconds: 15 }


      enabled:
        kubernetes: true
        techdocs: true
        argocd: true
        sonarqube: false
        keycloak: false  # true -> false
        ocm: true
        github: false
        githubOrg: false
        gitlab: true
        jenkins: false
        permission: false

        azure: true
        azureDevOps: true
        microsoftGraphOrg: true
        keycloakOrg: false
        microsoft: true
        azureEasyAuth: false

  service:
    ports:
      backend: 4180
      targetPort: backend

result

It turn out the hack works, the user is created with azure oid as username.

azure sso as openshift idp

golden path template

There is a golden path template for backstage, you can use it to create a new backstage app.

we will use this template for test:

New repo created in azure devops:

Go back to rhdh, we can see new component created.

dev space

Add user to org and project.

Login using user in the org.

Set your personal access token

Copy the token generate

Access the dev space in openshift

There is only 4 provider right now

import and create the workspace

The devfile generated

schemaVersion: 2.1.0
metadata:
  attributes:
    metadata-name-field: generateName
    metadata-name-original-value: dummy-repo-01
  name: dummy-repo-01
  namespace: user1-devspaces
attributes:
  che-theia.eclipse.org/sidecar-policy: mergeImage
projects:
  - attributes: {}
    name: dummy-repo-01
    git:
      remotes:
        origin: https://dev.azure.com/wangzheng422/demo/_git/dummy-repo-01
components:
  - name: universal-developer-image
    container:
      image: registry.redhat.io/devspaces/udi-rhel8@sha256:022cc606ec53638f7079a638f0810fee3a1717b42426bcfa31c2ba2e78520c54
commands: []

You can see the code editor webUI now.

make some change to see whether git push works.

git push ok

todo

  1. The dev space link can be integrated into rhdh, we will show how to later.
  2. integrate with azure ad/sso

The offical document is here

For our azure devops env, we can not link it to auzre ad/entra right now, because subscription/license issue. So we can not test the sso integration now.

end