Browse Source

see #46: Allow setting the OAuth flows per service

pull/50/head
Nicolas Massé 7 years ago
parent
commit
09b51a1c87
  1. 12
      README.md
  2. 1
      defaults/main.yml
  3. 20
      tasks/api-calls/update_oidc_configuration.yml
  4. 12
      tasks/main.yml
  5. 14
      tasks/steps/default_application.yml
  6. 29
      tasks/steps/discover_platform.yml
  7. 30
      tasks/steps/discover_service.yml
  8. 6
      tasks/steps/oidc_configuration.yml
  9. 14
      tasks/steps/read_openapi.yml
  10. 11
      templates/api-calls/update_oidc_configuration.j2
  11. 14
      tests/test-cases/02-echo-api-oidc.yml

12
README.md

@ -501,6 +501,18 @@ installed in `{{ threescale_cicd_local_bin_path }}`.
- `threescale_cicd_goswagger_command=/usr/local/bin/swagger`
- `threescale_cicd_local_bin_path=/tmp`
### `threescale_cicd_oicd_flows`
Override or update the list of supported OAuth flows for this API.
- **Syntax:** array of strings (`[ 'application', 'accessCode' ]`)
- **Required:** no
- **Default value:** the `flow` field of the `securityScheme` object in your
OpenAPI Specification file.
- **Examples:**
- `threescale_cicd_oicd_flows="{{ [ 'application', 'accessCode' ] }}"` (override the flow list)
- `threescale_cicd_oicd_flows="{{ [ 'application', threescale_cicd_api_security_scheme.flow ] }}"` (add a flow)
### Miscellaneous variables
Miscellaneous variables defined in [defaults/main.yml](defaults/main.yml)

1
defaults/main.yml

@ -162,3 +162,4 @@ threescale_cicd_smoke_test_url: '{{ lookup(''template'', ''api-calls/smoke-test/
threescale_cicd_promote_proxy_payload: '{{ lookup(''template'', ''api-calls/promote_proxy.j2'') }}'
threescale_cicd_update_activedoc_payload: '{{ lookup(''template'', ''api-calls/update_activedoc.j2'') }}'
threescale_cicd_create_activedoc_payload: '{{ lookup(''template'', ''api-calls/create_activedoc.j2'') }}'
threescale_cicd_update_oidc_configuration_payload: '{{ lookup(''template'', ''api-calls/update_oidc_configuration.j2'') }}'

20
tasks/api-calls/update_oidc_configuration.yml

@ -0,0 +1,20 @@
---
- debug:
var: threescale_cicd_update_oidc_configuration_payload
verbosity: 1
no_log: '{{ threescale_cicd_nolog }}'
- name: Update the proxy definition
uri:
url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}/proxy/oidc_configuration.json
validate_certs: no
method: PATCH
body: '{{ threescale_cicd_update_oidc_configuration_payload }}'
register: threescale_cicd_tmpresponse
changed_when: 'threescale_cicd_tmpresponse.status == 200'
no_log: '{{ threescale_cicd_nolog }}'
- name: Wait for a couple seconds
pause:
seconds: '{{ threescale_cicd_throttling }}'

12
tasks/main.yml

@ -11,11 +11,14 @@
# Warn the user about those deprecated features
- import_tasks: steps/variables_from_inventory.yml
# Discover the current state of the platform
- import_tasks: steps/discover_platform.yml
# Load the API definition from the provided OpenAPI file
- import_tasks: steps/read_openapi.yml
# Discover the current state of the platform
- import_tasks: steps/discover.yml
# Discover the current state of the service
- import_tasks: steps/discover_service.yml
# Create or update the service definition
- import_tasks: steps/service.yml
@ -29,6 +32,9 @@
# Update the proxy
- import_tasks: steps/proxy.yml
# Update the OIDC configuration
- import_tasks: steps/oidc_configuration.yml
# Create or update policies
- import_tasks: steps/policies.yml
@ -45,7 +51,7 @@
threescale_cicd_smoke_test_env: staging
when: >-
threescale_cicd_openapi_smoketest_operation|length > 0 and threescale_cicd_application_plans is defined
and threescale_cicd_apicast_sandbox_endpoint != threescale_cicd_apicast_production_endpoint
and threescale_cicd_apicast_discovered_sandbox_endpoint != threescale_cicd_apicast_discovered_production_endpoint
# Promote to production
- import_tasks: steps/promote.yml

14
tasks/steps/default_application.yml

@ -15,9 +15,13 @@
## When using OAuth / OIDC authentication, we need to patch the Keycloak client
## to support the client_credentials grant.
##
## Note: only happens on 3scale AMP < 2.5. Later versions do not need this.
##
- include_tasks: api-calls/keycloak/authenticate.yml
when: "threescale_cicd_api_security_scheme.type == 'oauth2'"
when: >-
threescale_cicd_api_security_scheme.type == 'oauth2'
and not threescale_cicd_capabilities.oidc_configuration_api|bool
vars:
oauth_payload:
client_id: '{{ threescale_cicd_sso_issuer_endpoint|urlsplit(''username'') }}'
@ -26,7 +30,11 @@
grant_type: 'client_credentials'
- include_tasks: api-calls/keycloak/wait_for_client.yml
when: "threescale_cicd_api_security_scheme.type == 'oauth2'"
when: >-
threescale_cicd_api_security_scheme.type == 'oauth2'
and not threescale_cicd_capabilities.oidc_configuration_api|bool
- include_tasks: api-calls/keycloak/patch_client.yml
when: "threescale_cicd_api_security_scheme.type == 'oauth2'"
when: >-
threescale_cicd_api_security_scheme.type == 'oauth2'
and not threescale_cicd_capabilities.oidc_configuration_api|bool

29
tasks/steps/discover.yml → tasks/steps/discover_platform.yml

@ -25,35 +25,6 @@
var: threescale_cicd_existing_services_details
verbosity: 1
- name: Get the list of existing application plans
uri:
url: '{{ service_url }}/application_plans.json?access_token={{ threescale_cicd_access_token|urlencode }}'
validate_certs: no
register: threescale_cicd_tmpresponse
when: threescale_cicd_api_system_name in threescale_cicd_existing_services
no_log: '{{ threescale_cicd_nolog }}'
vars:
service_url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}
- name: Set the list of existing application plans as a fact
set_fact:
threescale_cicd_existing_application_plans: >-
{{ threescale_cicd_tmpresponse.json|json_query('plans[*].application_plan.system_name')
if threescale_cicd_api_system_name in threescale_cicd_existing_services
else [] }}
threescale_cicd_existing_application_plans_details: >-
{{ threescale_cicd_tmpresponse.json|json_query('plans[].{"system_name": application_plan.system_name, "id": application_plan.id}')
if threescale_cicd_api_system_name in threescale_cicd_existing_services
else [] }}
- debug:
msg: "Found {{ threescale_cicd_existing_application_plans|length }} application plans"
verbosity: 1
- debug:
var: threescale_cicd_existing_application_plans_details
verbosity: 1
- name: Retrieve existing ActiveDocs from the 3scale Admin Portal
uri:
url: "https://{{ inventory_hostname }}/admin/api/active_docs.json?access_token={{ threescale_cicd_access_token|urlencode }}"

30
tasks/steps/discover_service.yml

@ -0,0 +1,30 @@
---
- name: Get the list of existing application plans
uri:
url: '{{ service_url }}/application_plans.json?access_token={{ threescale_cicd_access_token|urlencode }}'
validate_certs: no
register: threescale_cicd_tmpresponse
when: threescale_cicd_api_system_name in threescale_cicd_existing_services
no_log: '{{ threescale_cicd_nolog }}'
vars:
service_url: https://{{ inventory_hostname }}/admin/api/services/{{ threescale_cicd_api_service_id }}
- name: Set the list of existing application plans as a fact
set_fact:
threescale_cicd_existing_application_plans: >-
{{ threescale_cicd_tmpresponse.json|json_query('plans[*].application_plan.system_name')
if threescale_cicd_api_system_name in threescale_cicd_existing_services
else [] }}
threescale_cicd_existing_application_plans_details: >-
{{ threescale_cicd_tmpresponse.json|json_query('plans[].{"system_name": application_plan.system_name, "id": application_plan.id}')
if threescale_cicd_api_system_name in threescale_cicd_existing_services
else [] }}
- debug:
msg: "Found {{ threescale_cicd_existing_application_plans|length }} application plans"
verbosity: 1
- debug:
var: threescale_cicd_existing_application_plans_details
verbosity: 1

6
tasks/steps/oidc_configuration.yml

@ -0,0 +1,6 @@
---
- include_tasks: api-calls/update_oidc_configuration.yml
when: >-
threescale_cicd_api_security_scheme.type == 'oauth2'
and threescale_cicd_capabilities.oidc_configuration_api|bool

14
tasks/steps/read_openapi.yml

@ -46,5 +46,19 @@
msg: "The smoketest operation {{ threescale_cicd_openapi_smoketest_operation }} must be a GET and cannot have a placeholder in its path."
when: 'threescale_cicd_openapi_smoketest_operation|length > 0'
- name: Make sure the 'application' OAuth flow is enabled if smoke tests are required
assert:
that:
- "'application' in threescale_cicd_oicd_flows|default([ threescale_cicd_api_security_scheme.flow ])"
msg: >-
Since 3scale AMP 2.5, you need to explicitely add the "application" flow to the supported
OAuth flows if you want to run smoke tests. You can either disable smoke tests
(-e threescale_cicd_openapi_smoketest_operation="") or enable the application flow
(-e threescale_cicd_oicd_flows="{{ [ 'application', threescale_cicd_api_security_scheme.flow ] }}").
when: >-
threescale_cicd_api_security_scheme.type == 'oauth2'
and threescale_cicd_openapi_smoketest_operation|length > 0
and threescale_cicd_capabilities.oidc_configuration_api|bool
- debug:
msg: "Will work on service with system_name = {{ threescale_cicd_api_system_name }}"

11
templates/api-calls/update_oidc_configuration.j2

@ -0,0 +1,11 @@
{% set flows = threescale_cicd_oicd_flows|default([ threescale_cicd_api_security_scheme.flow ]) %}
{%
set payload = [
'access_token=' ~ threescale_cicd_access_token|urlencode,
'implicit_flow_enabled=' ~ ('true' if 'implicit' in flows else 'false'),
'direct_access_grants_enabled=' ~ ('true' if 'password' in flows else 'false'),
'service_accounts_enabled=' ~ ('true' if 'application' in flows else 'false'),
'standard_flow_enabled=' ~ ('true' if 'accessCode' in flows else 'false'),
]
%}
{{ payload|join("&") }}

14
tests/test-cases/02-echo-api-oidc.yml

@ -5,27 +5,17 @@
gather_facts: no
vars:
threescale_cicd_openapi_file: '{{ playbook_dir }}/api-contracts/echo-api-oidc.yaml'
threescale_cicd_oicd_flows: "{{ [ 'application', threescale_cicd_api_security_scheme.flow ] }}"
tasks:
# With 3scale SaaS, there is a race condition where Zync would update the SSO client
# after we patched it and thus reverts our changes.
#
# As a temporary fix the smoke tests are disabled with OIDC in the SaaS environment
- name: Generate a random system_name for this test run
import_tasks: "common/random-system-name.yml"
# Test a first deployment
- import_role:
name: 'nmasse-itix.threescale-cicd'
vars:
# TODO: remove me as soon as proper OIDC support is implemented for SaaS
threescale_cicd_openapi_smoketest_operation: '{{ '''' if inventory_hostname is match(".*[.]3scale[.]net") else ''Echo'' }}'
# Verify idempotence
- import_role:
name: 'nmasse-itix.threescale-cicd'
vars:
# TODO: remove me as soon as proper OIDC support is implemented for SaaS
threescale_cicd_openapi_smoketest_operation: '{{ '''' if inventory_hostname is match(".*[.]3scale[.]net") else ''Echo'' }}'
# Delete the service
- import_role:
name: 'nmasse-itix.threescale-cicd'

Loading…
Cancel
Save