GNU/Linux ◆ xterm ◆ bash 415 views

SCITT OIDC Auth

Dependencies

Install the SCITT API Emulator with the oidc extra.

$ pip install -e .[oidc]

Usage example with GitHub Actions

Expose the server to the internet. localhost.run or ngrok are common options if you need to exposed a NAT’d machine.

$ ssh -nT -R 80:localhost:8080 nokey@localhost.run 2>/dev/null | grep --line-buffered 'tunneled with tls' | python -c 'import sys; print(sys.stdin.readline().split()[-1])' | tee public-url.txt &
$ export SCITT_URL=$(cat public-url.txt)

Create the middleware config file. Set config audience to the publicly accessible URL of the SCITT instance.

oidc-middleware-config.yaml

audience: $SCITT_URL
issuers:
- https://token.actions.githubusercontent.com
claim_schema:
  https://token.actions.githubusercontent.com:
    $schema: https://json-schema.org/draft/2020-12/schema
    properties:
      job_workflow_ref:
        enum:
        - ${WORKFLOW_REF}
        type: string
      job_workflow_sha:
        enum:
        - ${JOB_WORKFLOW_SHA}
        type: string
      repository_id:
        enum:
        - ${REPOSITORY_ID}
        type: string
      repository_owner_id:
        enum:
        - ${REPOSITORY_OWNER_ID}
        type: string
    required:
    - job_workflow_ref
    - job_workflow_sha
    - repository_owner_id
    - repository_id

Start the SCITT instance using the OIDCAuthMiddleware and associated config.

$ scitt-emulator server --port 8080 --workspace workspace/ --tree-alg CCF \
    --middleware scitt_emulator.oidc:OIDCAuthMiddleware \
    --middleware-config-path oidc-middleware-config.json

Create GitHub Actions Workflow.

name: "SCITT Notary"

on:
  push:
    branches:
      - main
    paths-ignore:
      - '**.md'
  workflow_dispatch:
    inputs:
      scitt-url:
        description: 'URL of SCITT instance'
        type: string
      payload:
        description: 'Payload for claim'
        default: ''
        type: string
  workflow_call:
    inputs:
      scitt-url:
        description: 'URL of SCITT instance'
        type: string
      payload:
        description: 'Payload for claim'
        type: string

jobs:
  notarize:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    env:
      SCITT_URL: '${{ inputs.scitt-url || github.event.inputs.scitt-url }}'
      PAYLOAD: '${{ inputs.payload || github.event.inputs.payload }}'
    steps:
      - name: Set defaults if env vars not set (as happens with on.push trigger)
        run: |
          if [[ "x${SCITT_URL}" = "x" ]]; then
            echo "SCITT_URL=http://localhost:8080" >> "${GITHUB_ENV}"
          fi
          if [[ "x${PAYLOAD}" = "x" ]]; then
            echo 'PAYLOAD={"key": "value"}' >> "${GITHUB_ENV}"
          fi
      - uses: actions/checkout@v4
      - name: Set up Python 3.8
        uses: actions/setup-python@v4
        with:
          python-version: 3.8
      - name: Install SCITT API Emulator
        run: |
          pip install -U pip setuptools wheel
          pip install .[oidc]
      - name: Install github-script dependencies
        run: |
          npm install @actions/core
      - name: Get OIDC token to use as bearer token for auth to SCITT
        uses: actions/github-script@v6
        id: github-oidc
        with:
          script: |
            const {SCITT_URL} = process.env;
            core.setOutput('token', await core.getIDToken(SCITT_URL));
      - name: Create claim
        run: |
          scitt-emulator client create-claim --issuer did:web:example.org --content-type application/json --payload "${PAYLOAD}" --out claim.cose
      - name: Submit claim
        env:
          OIDC_TOKEN: '${{ steps.github-oidc.outputs.token }}'
          WORKFLOW_REF: '${{ github.workflow_ref }}'
          # Use of job_workflow_sha blocked by
          # https://github.com/actions/runner/issues/2417#issuecomment-1718369460
          JOB_WORKFLOW_SHA: '${{ github.sha }}'
          REPOSITORY_OWNER_ID: '${{ github.repository_owner_id }}'
          REPOSITORY_ID: '${{ github.repository_id }}'
        run: |
          # Create the middleware config file
          tee oidc-middleware-config.json <<EOF
          {
              "issuers": ["https://token.actions.githubusercontent.com"],
              "claim_schema": {
                  "https://token.actions.githubusercontent.com": {
                        "\$schema": "https://json-schema.org/draft/2020-12/schema",
                        "required": [
                            "job_workflow_ref",
                            "job_workflow_sha",
                            "repository_owner_id",
                            "repository_id"
                        ],
                        "properties": {
                            "job_workflow_ref": {
                                "type": "string",
                                "enum": [
                                    "${WORKFLOW_REF}"
                                ]
                            },
                            "job_workflow_sha": {
                                "type": "string",
                                "enum": [
                                    "${JOB_WORKFLOW_SHA}"
                                ]
                            },
                            "repository_owner_id": {
                                "type": "string",
                                "enum": [
                                    "${REPOSITORY_OWNER_ID}"
                                ]
                            },
                            "repository_id": {
                                "type": "string",
                                "enum": [
                                    "${REPOSITORY_ID}"
                                ]
                            }
                        }
                    }
              },
              "audience": "${SCITT_URL}"
          }
          EOF
          # Start SCITT using the `OIDCAuthMiddleware` and associated config.
          if [[ "x${SCITT_URL}" = "xhttp://localhost:8080" ]]; then
            scitt-emulator server --port 8080 --workspace workspace/ --tree-alg CCF \
              --middleware scitt_emulator.oidc:OIDCAuthMiddleware \
              --middleware-config-path oidc-middleware-config.json &
            sleep 1s
          fi
          # Submit the claim using OIDC token as auth
          scitt-emulator client submit-claim --token "${OIDC_TOKEN}" --url "${SCITT_URL}" --claim claim.cose --out claim.receipt.cbor

Dispatch GitHub Actions Workflow.

$ gh -R scitt-community/scitt-api-emulator workflow run notarize.yml -F scitt-url=$(cat public-url.txt)

Check SCITT instance logs

Leaf hash: 2c58c822a8344b9fa14d247987977eaa3719dbe02df74169d3893ed6365bb181
Root: 0d5ae584ce5c9aac751d6b6ad79e1d61fd7c51933c45b127409e6147abdab4e2
Receipt written to workspace/storage/2.receipt.cbor
Claim written to workspace/storage/2.cose
127.0.0.1 - - [12/Sep/2023 22:31:08] "POST /entries HTTP/1.1" 201 -
127.0.0.1 - - [12/Sep/2023 22:31:09] "GET /entries/2/receipt HTTP/1.1" 200 -

Basic GitHub Action Reusable Workflow OIDC validation support as used by slsa generator TS submission and others requires validating claims to do workload based identity where the workload is identified by job_workflow_ref, job_workflow_sha, repository_owner_id, and repository_id claims.

audience: http://localhost:8080
issuers:
- https://token.actions.githubusercontent.com
claim_schema:
  https://token.actions.githubusercontent.com:
    required:
    - job_workflow_ref
    - job_workflow_sha
    - repository_owner_id
    - repository_id
    properties:
      job_workflow_ref:
        enum:
        - 'pdxjohnny/scitt-api-emulator/.github/workflows/notarize.yml@refs/heads/auth'
        type: string
      job_workflow_sha:
        enum:
        - '215777b7ea418f1e0bd54f39cc70467e1fb76b8e'
        type: string
      repository_id:
        enum:
        - '621131680'
        type: string
      repository_owner_id:
        enum:
        - '5950433'
        type: string