diff --git a/.github/workflows/tyk-assets-cicd.yml b/.github/workflows/tyk-assets-cicd.yml index 6209ed0..40bd931 100644 --- a/.github/workflows/tyk-assets-cicd.yml +++ b/.github/workflows/tyk-assets-cicd.yml @@ -12,11 +12,10 @@ on: - 'dev/**' jobs: - # Run linter and validation workflow + # Set up dev APIs and Policies tyk-dev-env: - uses: ./.github/workflows/tyk-lint.yml - with: - environment: 'dev' + uses: ./.github/workflows/tyk-dev.yml + secrets: inherit # Set up staging APIs and Policies if the Dev assets pass the linter / validation tyk-staging-env: diff --git a/.github/workflows/tyk-env-promotion.yml b/.github/workflows/tyk-env-promotion.yml index 65476f1..b121432 100644 --- a/.github/workflows/tyk-env-promotion.yml +++ b/.github/workflows/tyk-env-promotion.yml @@ -1,4 +1,4 @@ -name: Tyk assets environment promotion +name: Tyk Assets Environment Promotion # Perform the env promotion only on push to main branch on: @@ -19,29 +19,29 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@v4 - # - name: Create .tyk.json - # run: | - # cd ./stg - # echo '{' > .tyk.json - # echo ' "type": "apidef",' >> .tyk.json - # echo ' "files": [' >> .tyk.json - # find . -type f -name '*.json' -path './apis/*' -exec echo ' {"file": "{}"},' \; | sed '$ s/,$//' >> .tyk.json - # echo ' ],' >> .tyk.json - # echo ' "policies": [' >> .tyk.json - # find . -type f -name '*.json' -path './policies/*' -exec echo ' {"file": "{}"},' \; | sed '$ s/,$//' >> .tyk.json - # echo ' ],' >> .tyk.json - # echo ' "assets": [' >> .tyk.json - # find . -type f -name '*.json' -path './assets/*' -exec echo ' {"file": "{}"},' \; | sed '$ s/,$//' >> .tyk.json - # echo ' ]' >> .tyk.json - # echo '}' >> .tyk.json - # cat .tyk.json + - name: Create .tyk.json + run: | + cd ./${{ inputs.environment }} + echo '{' > .tyk.json + echo ' "type": "apidef",' >> .tyk.json + echo ' "files": [' >> .tyk.json + find . -type f -name '*.json' -path './apis/*' -exec echo ' {"file": "{}"},' \; | sed '$ s/,$//' >> .tyk.json + echo ' ],' >> .tyk.json + echo ' "policies": [' >> .tyk.json + find . -type f -name '*.json' -path './policies/*' -exec echo ' {"file": "{}"},' \; | sed '$ s/,$//' >> .tyk.json + echo ' ],' >> .tyk.json + echo ' "assets": [' >> .tyk.json + find . -type f -name '*.json' -path './assets/*' -exec echo ' {"file": "{}"},' \; | sed '$ s/,$//' >> .tyk.json + echo ' ]' >> .tyk.json + echo '}' >> .tyk.json + cat .tyk.json - # - name: Sync with Tyk - # env: - # TYK_SYNC_REPO: ${{ vars.TYK_SYNC_REPO }} - # TYK_SYNC_VERSION: ${{ vars.TYK_SYNC_VERSION }} - # TYK_DASHBOARD_URL: ${{ secrets.TYK_DASHBOARD_URL }} - # TYK_DASHBOARD_SECRET: ${{ secrets.TYK_DASHBOARD_SECRET }} - # run: | - # docker run ${TYK_SYNC_REPO}:${TYK_SYNC_VERSION} version - # docker run -v ${{ github.workspace }}:/app/data ${TYK_SYNC_REPO}:${TYK_SYNC_VERSION} sync --path /app/data --dashboard ${TYK_DASHBOARD_URL} --secret ${TYK_DASHBOARD_SECRET} \ No newline at end of file + - name: Sync with Tyk + env: + TYK_SYNC_REPO: ${{ vars.TYK_SYNC_REPO }} + TYK_SYNC_VERSION: ${{ vars.TYK_SYNC_VERSION }} + TYK_DASHBOARD_URL: ${{ inputs.environment == 'stg' && secrets.TYK_STG_DASHBOARD_URL || secrets.TYK_PROD_DASHBOARD_URL }} + TYK_DASHBOARD_SECRET: ${{ inputs.environment == 'stg' && secrets.TYK_STG_DASHBOARD_SECRET || secrets.TYK_PROD_DASHBOARD_SECRET }} + run: | + docker run ${TYK_SYNC_REPO}:${TYK_SYNC_VERSION} version + docker run -v ${{ github.workspace }}/${{ inputs.environment }}:/app/data ${TYK_SYNC_REPO}:${TYK_SYNC_VERSION} sync --path /app/data --dashboard ${TYK_DASHBOARD_URL} --secret ${TYK_DASHBOARD_SECRET} \ No newline at end of file diff --git a/README.md b/README.md index 7a2c814..2b0f958 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,109 @@ -# tyk-cicd-dev-demo -Demo of CICD using Tyk Sync and GH Actions -Configuration Example +# Tyk CICD Example using Tyk Sync (WIP) +This project demonstrates how to create a GitOps/CICD pipeline for API Management with Tyk. It shows secure and effective ways to promote assets from lower to upper environments using accessible tools like [Tyk Sync](https://tyk.io/docs/product-stack/tyk-sync/overview/), [Spectral](https://github.com/stoplightio/spectral), and Shell Scripting. These solutions are just examples and not the only ways to address common DevOps challenges in the API promotion workflow. + +## Overview +This repository assumes you have three standard environments: `dev`, `staging`, and `production`. The diagram below shows how these environments relate to each other and illustrates the workflow from development to staging and then to production. + +![Screenshot of an example CICD workflow demonstrating the Tyk asset promotion between environments](./assets/imgs/tyk-cicd-workflow-example.png) + + +Example VCS folder structure +``` +├── infrastructure + ├── dev + │ └── tyk + │ ├── apis + │ ├── assets + │ └── policies + ├── production + │ └── tyk + │ ├── apis + │ ├── assets + │ └── policies + └── staging + └── tyk + ├── apis + ├── assets + └── policies +``` + +The GitHub Action workflow files may look a bit messy because they demonstrate various methods for API linting and validation. By using different solutions like Shell Scripts and Spectral linting, the goal is to showcase all possible options available for these tasks. + +You can review the complete CICD pipeline here: [https://github.com/TykTechnologies/tyk-cicd-dev-demo/actions/runs/10923225077](https://github.com/TykTechnologies/tyk-cicd-dev-demo/actions/runs/10923225077) + + +## Getting Started +### Prerequisites +1. Two Tyk environments that can be acceesible + +### Steps +#### Step 1: Clone this repository and set up your GitHub repositories with two environments named staging and production. + +#### Step 2: Configure GitHub Security for each deployment (staging and production) +Repository variables example ``` +TYK_SYNC_REPO=tykio/tyk-sync +TYK_SYNC_VERSION=v1.5.1 +``` + +Repository secrets example +``` +TYK_STG_DASHBOARD_SECRET={TYK_DASHBOARD_API_CREDENTIALS} +TYK_STG_DASHBOARD_URL={TYK_DASHBOARD_URL} STG_US_CONFIG_DATA={\"routes\": {\"default\": \"https://stg.httpbin.com\",\"stg1\": \"https://stg1.httpbin.com\",\"stg2\": \"https://stg2.httpbin.com\"}} STG_US_PROXY_TARGET_URL=http://httpbin.org/get?env=stg +TYK_PROD_DASHBOARD_SECRET={TYK_DASHBOARD_API_CREDENTIALS} +TYK_PROD_DASHBOARD_URL={TYK_DASHBOARD_URL} PROD_US_CONFIG_DATA={\"routes\": {\"default\": \"https://prod.httpbin.com\",\"prod1\": \"https://prod1.httpbin.com\",\"prod2\": \"https://prod2.httpbin.com\"}} PROD_US_PROXY_TARGET_URL=http://httpbin.org/get?env=prod ``` -Tyk Sync Dump Command Example + +## Useful Resources +Tyk Sync Dump Example Command ``` -docker run -it --rm -v $(pwd):/tmp/data tykio/tyk-sync:v1.5.1 dump -d="http://host.docker.internal:3000" -s="{TYK_DASHBOARD_API_CREDENTIAL}" -t="/tmp/data" --apis="{API_ID}" +docker run -it --rm -v $(pwd):/tmp/data tykio/tyk-sync:v1.5.1 dump -d="{TYK_DASHBOARD_URL}" -s="{TYK_DASHBOARD_API_CREDENTIAL}" -t="/tmp/data" --apis="{API_ID}" ``` -Execute Pipeline using Act Example +Local GH Action Development Using [act](https://nektosact.com/) Example Command ``` act push -s STG_US_CONFIG_DATA={\"hello\"\:\"world\"} -s ORG_NAME=tyk -s ORG_EMAIL=long@tyk.io -s STG_US_PROXY_TARGET_URL=httpbin2.org ``` Spectral / Stoplight Ruleset Example ``` - # no-empty-target-url: - # description: APIs must have a target_url - # given: "$.api_definition.proxy" - # severity: error - # then: - # field: 'target_url' - # function: 'pattern' - # functionOptions: - # match: '^(?!\s*$).+' - - # check-for-mtls-auth: - # description: MutualTLS is not enabled - # given: "$.api_definition" - # severity: warning - # then: - # field: enable_jwt - # function: falsy - - # ensure-authentication-method: - # description: "Ensure that at least one of 'enable_jwt' or 'use_mutual_tls_auth' is true." - # given: "$.api_definition" - # then: - # - field: "enable_jwt" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # - field: "use_mutual_tls_auth" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # severity: error - # message: "At least one of 'api_definition.enable_jwt' or 'api_definition.use_mutual_tls_auth' must be true." +rules: + no-empty-target-url: + description: APIs must have a target_url + given: "$.api_definition.proxy" + severity: error + then: + field: 'target_url' + function: 'pattern' + functionOptions: + match: '^(?!\s*$).+' + + check-for-mtls-auth: + description: MutualTLS is not enabled + given: "$.api_definition" + severity: warning + then: + field: enable_jwt + function: falsy + + validate-auth-methods: + description: "Ensure that at least one of 'enable_jwt' or 'use_mutual_tls_auth' is true." + given: "$.api_definition" + then: + - field: "enable_jwt" + function: truthy + functionOptions: + negation: true # Should not be false + - field: "use_mutual_tls_auth" + function: truthy + functionOptions: + negation: true # Should not be false + severity: error + message: "At least one of 'api_definition.enable_jwt' or 'api_definition.use_mutual_tls_auth' must be true." ``` \ No newline at end of file diff --git a/assets/imgs/tyk-cicd-workflow-example.png b/assets/imgs/tyk-cicd-workflow-example.png new file mode 100644 index 0000000..fce2f58 Binary files /dev/null and b/assets/imgs/tyk-cicd-workflow-example.png differ diff --git a/dev/tykapi-ruleset.yaml b/dev/tykapi-ruleset.yaml index 1d799cd..fe0c5f0 100644 --- a/dev/tykapi-ruleset.yaml +++ b/dev/tykapi-ruleset.yaml @@ -15,19 +15,4 @@ rules: field: 'target_url' function: pattern functionOptions: - match: '^(?!\s*$).+' - - # check-authentication-methods: - # description: "At least one of 'enable_jwt' or 'use_mutual_tls_auth' must be true." - # given: "$.api_definition" - # then: - # - field: "enable_jwt" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # - field: "use_mutual_tls_auth" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # severity: error - # message: "At least one of 'api_definition.enable_jwt' or 'api_definition.use_mutual_tls_auth' must be true." \ No newline at end of file + match: '^(?!\s*$).+' \ No newline at end of file diff --git a/prod/tykapi-ruleset.yaml b/prod/tykapi-ruleset.yaml index 1d799cd..fe0c5f0 100644 --- a/prod/tykapi-ruleset.yaml +++ b/prod/tykapi-ruleset.yaml @@ -15,19 +15,4 @@ rules: field: 'target_url' function: pattern functionOptions: - match: '^(?!\s*$).+' - - # check-authentication-methods: - # description: "At least one of 'enable_jwt' or 'use_mutual_tls_auth' must be true." - # given: "$.api_definition" - # then: - # - field: "enable_jwt" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # - field: "use_mutual_tls_auth" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # severity: error - # message: "At least one of 'api_definition.enable_jwt' or 'api_definition.use_mutual_tls_auth' must be true." \ No newline at end of file + match: '^(?!\s*$).+' \ No newline at end of file diff --git a/stg/tykapi-ruleset.yaml b/stg/tykapi-ruleset.yaml index 1d799cd..fe0c5f0 100644 --- a/stg/tykapi-ruleset.yaml +++ b/stg/tykapi-ruleset.yaml @@ -15,19 +15,4 @@ rules: field: 'target_url' function: pattern functionOptions: - match: '^(?!\s*$).+' - - # check-authentication-methods: - # description: "At least one of 'enable_jwt' or 'use_mutual_tls_auth' must be true." - # given: "$.api_definition" - # then: - # - field: "enable_jwt" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # - field: "use_mutual_tls_auth" - # function: truthy - # functionOptions: - # negation: true # Should not be false - # severity: error - # message: "At least one of 'api_definition.enable_jwt' or 'api_definition.use_mutual_tls_auth' must be true." \ No newline at end of file + match: '^(?!\s*$).+' \ No newline at end of file