Import Swagger to Define and Control API Groups

Objective

This guide provides instructions on how to import a Swagger file to define API groups and set rules to control access to APIs, enabling granular API access control ability. To know more about security concepts, see Security.

Enabling this feature includes preparing the Swagger files for your API definitions, importing them to F5 Distributed Cloud Services, and applying them to your load balancer. Using the instructions provided in this guide, you can import swagger files, attach to your load balancer, and apply service policies to restrict access to the API groups defined in the Swagger files.


Prerequisites

The following prerequisites apply:

  • Note: For instructions on how to delegate your domain to F5 Distributed Cloud, see HTTP Load Balancer. See the vK8s Deployment guide for deploying your applications on the F5 Distributed Cloud's Network Cloud or Edge Cloud.

Configuration

Importing Swagger files to define API groups and controlling access to those groups includes the following sequences of activities:

  • Prepare Swagger files containing API groups and definitions and import them using Console.
  • Define service policy to control access to the API groups.

Note: You can create API definition as part of HTTP load balancer configuration or separately using the Manage > API Definition option. This guide presents instructions to create a separate API definition and later apply them to load balancer.


Import Swagger Files and Create API Definitions

Do the following to prepare and import Swagger files containing API groups and definitions.

Step 1: Prepare Swagger files.

Prepare Swagger files on your local machine with the API groups and definitions as per your requirement. The following are sample files for your reference. Here one file is for user API and other is for REST API.

Note: You can add tags to the API groups to identify and apply controls based on the tags. For example, you can specify the x-volterra-api-group tag with value such as sensitive to denote that access to this group must be tightly controlled. The REST API file in the following samples specifies this tag.

User API
{
  "swagger": "2.0",
  "info": {
    "description": "Juice Shop User API",
    "title": "Juice Shop User API",
    "version": "v0"
  },
  "basePath": "/api",
  "schemes": [
    "http",
    "https"
  ],
  "paths": {
    "/Addresss": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Addresss/{id}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/BasketItems/": {
      "post": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "description": "",
            "in": "body",
            "name": "body",
            "schema": {
              "example": [
                "{\"ProductId\":6,\"BasketId\":\"6\",\"quantity\":1}",
                "{\"ProductId\":9,\"BasketId\":\"6\",\"quantity\":1}",
                "{\"ProductId\":24,\"BasketId\":\"6\",\"quantity\":1}"
              ],
              "properties": {
                "BasketId": {
                  "description": "Integer",
                  "pattern": "-?\\d+",
                  "type": "string"
                },
                "ProductId": {
                  "type": "integer"
                },
                "quantity": {
                  "type": "integer"
                }
              },
              "required": [
                "quantity",
                "BasketId",
                "ProductId"
              ],
              "type": "object"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/BasketItems/{id}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "description": "",
            "in": "body",
            "name": "body",
            "schema": {
              "example": [
                "{\"ProductId\":6,\"BasketId\":\"6\",\"quantity\":1}",
                "{\"ProductId\":9,\"BasketId\":\"6\",\"quantity\":1}",
                "{\"ProductId\":24,\"BasketId\":\"6\",\"quantity\":1}"
              ],
              "properties": {
                "BasketId": {
                  "description": "Integer",
                  "pattern": "-?\\d+",
                  "type": "string"
                },
                "ProductId": {
                  "type": "integer"
                },
                "quantity": {
                  "type": "integer"
                }
              },
              "required": [
                "quantity",
                "BasketId",
                "ProductId"
              ],
              "type": "object"
            }
          },
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Cards/{id}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Cards": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Cards/": {  
      "post": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Challenges/": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "description": "",
            "in": "query",
            "name": "name",
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Products/{id}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Quantitys/": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Deliverys": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/Deliverys/{id}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/SecurityAnswers": {
      "post": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "description": "",
            "in": "body",
            "name": "body",
            "schema": {
              "example": [
                "{\"UserId\":22,\"answer\":\"09/77/33\",\"SecurityQuestionId\":3}"
              ],
              "properties": {
                "SecurityQuestionId": {
                  "type": "integer"
                },
                "UserId": {
                  "type": "integer"
                },
                "answer": {
                  "description": "Integer",
                  "pattern": "-?\\d+",
                  "type": "string"
                }
              },
              "required": [
                "UserId",
                "SecurityQuestionId",
                "answer"
              ],
              "type": "object"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    }
  }
}

REST API
{
  "swagger": "2.0",
  "info": {
    "description": "Juice Shop REST",
    "title": "Juice Shop REST",
    "version": "v1"
  },
  "basePath": "/rest",
  "schemes": [
    "http",
    "https"
  ],
  "paths": {
    "/basket/{id}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/captcha": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/languages": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/memories": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/saveLoginIp": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/products/{id}/reviews": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      },
      "put": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/products/{id}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      },
      "post": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/basket/{id}/checkout": {
      "post": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/wallet/balance": {
     "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "x-volterra-api-group":"sensitive"
      }
    },
    "/track-order/{id}": {
    "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },
    "/user/whoami": {
    "get": {
        "consumes": [
          "application/json"
        ],
        "description": "Swagger auto-generated from learnt schema",
        "parameters": [
            
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "x-volterra-api-group":"sensitive"
      }    
    }
  }
}

Step 2: Log into Console and import Swagger files.
  • Switch to Web App & API Protection service and change to desired namespace.
  • Go to Manage > Files > Swagger Files. Click Add Swagger File.

nav swagger file
Figure: Swagger Files Page Path

  • Enter a name in the metadata section.
  • Go to Upload Swagger File section and click Upload File.

upload swagger
Figure: Upload Swagger Files

  • Select the Swagger file when prompted and click Upload.
  • Click Save and Exit to create the Swagger file objects in Console.
  • Repeat the previous steps for importing more Swagger files.
  • Click ... > Copy Latest Version's URL for a Swagger file object in Console to copy its path. This is useful to create API definitions in the next step.

copy url
Figure: Obtain Imported Swagger File URL

Step 3: Create API definitions and groups.
  • Go to Manage > API Management > API Definition. Click Add API Definition.
  • Enter a name in the metadata section.
  • Go to Swagger Specs section and click on the Enter swagger specs field.
  • Enter the Swagger file path you copied in previous step.
  • Click Add item and add entries for more Swagger files.

create apidef
Figure: Create API Definition

  • Click Save and Exit to create API definition objects in Console.
  • Click ... > Show Child Objects to view the list of API groups and API definitions. This example configures 3 API definition objects and the following is an example definition:

api definition 1
Figure: First API Group

  • Note down the names of the API definitions as this is used in the service policy rules to control access.

Create Service Policy to Control Access to APIs

Do the following to create service policies to control access to API groups based on API definitions and apply them to load balancer.

Step 1: Go to load balancers and start editing your load balancer.
  • Switch to Load Balancers service and change to desired namespace.
  • Select Manage > Load Balancers > HTTP Load Balancers. A list of load balancers is presented.
  • Click ... > Manage Configuration for your load balancer.
  • Click Edit Configuration on the manage configuration screen.
Step 2: Attach API definitions to load balancer.
  • Go to Security Configuration and enable the Show Advanced Fields option.
  • Scroll down to the API Definitions section and click Add item.

lb apidef
Figure: Apply API Definition to Load Balancer

  • Click on the Select API definition field and select the API definitions created in the previous section. You can use Add item to add more than one definitions.
Step 3: Start creating service policies.

In the same Security Configurationsection, scroll up do the following:

  • Select Apply Specified Service Policies for the Service Policies field.
  • Click Configure under the Apply Specified Service Policies field.
  • Click on the Select service policy field in the Policies screen and select Create new service policy option.
  • Enter a name for the policy in the metadata section and go to Rules section.
  • Select Custom Rule List for the Select Policy Rules field and click Configure under the Rules field.
Step 4: Start creating service policy rules.
  • Click Add item in the Rules screen.
  • Enter a name in the metadata section and click Configure in the Rule Specification section.
  • Select Allow for Action field in the Action section.
  • Scroll down to Advanced Match section and click Configure for the API Group Matcher field.
  • In the API Group Matcher screen, enter an API group name string in the Match field. You can use Add item option to specify more than one group.
  • Click Apply to add the matcher and click Apply to add the rule specification. Click Add item to add the rule.
  • Create one more rule using the Add item option in the rules section. Set Deny as the Action and spcficy another API group to which you want to deny access (for example, all base URLs).

This example configures the following rules:

  • The first rule allows the all-operations APIs.

allow all ops
Figure: API Matcher to Allow All Operational API URLs

  • The second rule denys the base-urls APIs.

deny base urls
Figure: Deny All Base URLs

  • The third rule allows rest all with the action as Allow. Note that there is no need of API matching for the third rule.

The sample order of service policy rules is as shown in the following image. This order is important as the rules are executed in the same order.

sp rules
Figure: Order of Rules for Service Policy

Note: This example creates a positive security model that only allows requests to operations that are specified in the swagger file for each specified base URL. Requests to all operations (path + method) specified in swagger files are allowed and requests to any unspecified operations under base URLs are denied. Requests sent to other URLs that do not match base URL are allowed.

Step 4: Complete creating service policy rules and policy.
  • Check that you created all rules as per your requirement. Click Apply in the Rules section.
  • Click Continue to add the the service policy to the load balancer.
  • Click Save and Exit to apply changes to load balancer configuration.

Concepts


API References