Provision API hub

You're viewing Apigee X documentation.
View Apigee Edge documentation.

This section describes how to provision the Apigee API hub using APIs. The following topics are discussed:

Define environment variables

Using environment variables ensures consistency and makes it easier for you to follow along in the documentation in later steps.

  1. Define the following environment variables, replacing the dynamic variables with your actual values:
    export TOKEN=$(gcloud auth print-access-token)
    export HOST="apigeeregistry.googleapis.com"
    
    # ----- Set key_ring_name and key_name to values that will help you identify the API hub encryption key in future. -----
    export KEY_RING_NAME="YOUR_KEY_RING_NAME"
    export KEY_NAME="YOUR_KEY_NAME"
    
    export PROJECT_ID="YOUR_PROJECT_ID"
    export RUNTIME_LOCATION="YOUR_RUNTIME_LOCATION"
    
    # -----If you already have a CMEK, define this environment variable-----
    export CMEK_KEY_ID="YOUR_CMEK_KEY_ID"
    

    Where:

    • TOKEN is the token that authenticates and authorizes your calls to the Apigee Registry APIs. It should be passed in Authentication headers as a bearer token. Note that the token expires after a period of time and when it does, you can simply regenerate it using the same command. For more information, see the reference page for the print-access-token command.
    • HOST is the service endpoint for API hub.
    • KEY_RING_NAME is the name of the key ring you will use to identify your encryption key ring.
    • KEY_NAME is the name of the key you will use to identify your API hub encryption key.
    • PROJECT_ID is the Cloud project ID that you created as part of Prerequisites.
    • RUNTIME_LOCATION is the physical location where the Apigee Registry instance you will create later is located.

    • CMEK_KEY_ID is the key ID of your customer-managed encryption key.

      The key ID has the following syntax (similar to a file path):

      projects/PROJECT_ID/locations/RUNTIME_LOCATION/keyRings/KEY_RING_NAME/cryptoKeys/KEY_NAME
      
  2. (Optional) Check your work by echoing the values you just set. Note that when you want to use a variable in your commands, precede the variable's name with a dollar sign ($).
    echo $TOKEN
    echo $HOST
    echo $KEY_RING_NAME
    echo $KEY_NAME
    echo $PROJECT_ID
    echo $RUNTIME_LOCATION
    
    # -----If you already have a CMEK-----
    echo $CMEK_KEY_ID
    
    

Create P4SA and CMEK

This section describes how to create a service account and an encryption key ring and key.

  1. Create an Apigee Registry per-product per-project service account (P4SA) for your project:

    gcloud beta services identity create --service=$HOST  --project=$PROJECT_ID
    

    The P4SA returned is similar to the following:

    service-PROJECT_NUMBER@gcp-sa-apigeeregistry.iam.gserviceaccount.com
    
  2. Put the created P4SA in a variable:

    export P4SA="YOUR_P4SA"
    
  3. Create a CMEK using KMS (Optional - you can use the CMEK associated with your runtime instance or create one here):

    1. Create a keyring:

      gcloud kms keyrings create $KEY_RING_NAME \
        --location $RUNTIME_LOCATION \
        --project $PROJECT_ID
      
    2. Create a key:

      gcloud kms keys create $KEY_NAME \
        --keyring $KEY_RING_NAME \
        --location $RUNTIME_LOCATION \
        --purpose "encryption" \
        --project $PROJECT_ID
      
    3. Verify that the key was created:

      gcloud kms keys list \
        --keyring $KEY_RING_NAME \
        --location $RUNTIME_LOCATION \
        --project $PROJECT_ID
      

      The key returned is similar to the following:

      projects/PROJECT_ID/locations/RUNTIME_LOCATION/keyRings/KEY_RING_NAME/cryptoKeys/KEY_NAME
      
    4. Put the created key in a variable:

      export CMEK_KEY_ID="projects/PROJECT_ID/locations/RUNTIME_LOCATION/keyRings/KEY_RING_NAME/cryptoKeys/KEY_NAME"
      
  4. Grant permission for P4SA on the CMEK:

    gcloud kms keys add-iam-policy-binding $KEY_NAME \
      --location $RUNTIME_LOCATION \
      --keyring $KEY_RING_NAME \
      --member serviceAccount:$P4SA \
      --role roles/cloudkms.cryptoKeyEncrypterDecrypter \
      --project $PROJECT_ID
    
    
  5. Verify your P4SA has roles/cloudkms.cryptoKeyEncrypterDecrypter permission on the CMEK.

    gcloud kms keys get-iam-policy $CMEK_KEY_ID
    

Create instance

In this section, you will create a single instance of API hub. Where instance is a globally-unique singleton. There can be only one instance globally. If an instance exists at location A, it cannot be created in location B.

Sample request

curl https://$HOST/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/instances?instance_id=default \
  -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
    "config": {
      "cmek_key_name": "'"$CMEK_KEY_ID"'"
  }
}'

Sample response

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": false
}

Common errors - bad input data

HTTP status code: 400 Bad Request
Error message: Instance is a singleton, and instance_id must be set to "default".
Possible cause: Setting instance_id to anything other than default.
Solution: Use default as your instance_id.
HTTP status code: 400 Bad Request
Error message: global is not a supported location to create Instance.
Possible cause: Setting global as location.
Solution: Use one of the supported runtime locations listed above.
HTTP status code: 401 Unauthorized
Error message: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.
Possible cause: Inavlid Auth Token.
Solution: The request token may be ill-formatted or expired. Regenerate auth token by running token="$(gcloud auth print-access-token)" and pass Authorization: Bearer ${token} as header.
HTTP status code: 403 PERMISSION_DENIED
Error message: Location RUNTIME_LOCATION is not found or access is unauthorized.
Possible cause: Setting location to an unsupported location.
Solution: Use one of the supported runtime locations listed above.
HTTP status code: 400 Bad Request
Error message: Instance.config.cmek_key_name must be provided to create Instance.
Possible cause: cmek_key_name is not provided in data.
Solution: Provide CMEK name. See Create P4SA and CMEK for detailed instructions.
HTTP status code: 400 Bad Request
Error message: Invalid key format: a valid key should be in the form of projects/PROJECT/locations/us-central1/keyRings/KEYRING/cryptoKeys/CRYPTOKEY.
Possible cause: cmek_key_name is ill-formatted.
Solution: Correct the key format.
HTTP status code: 400 Bad Request
Error message: CMEK key location needs to match the location of instance creation.
Possible cause: CMEK is in a different location.
Solution: Correct the location of the CMEK.
HTTP status code: 400 Bad Request
Error message: Apigee Registry P4SA must have roles/cloudkms.cryptoKeyEncrypterDecrypter permission on the CMEK key.
Possible cause: Apigee P4SA lacks permission on the CMEK. Note that we know only that the p4sa doesn't have the necessary permission. It's probable that the key doesn't exist at all, but we can't tell.
Solution: Verify that the key exists and that Apigee Registry P4SA has the required permission on the key.

Common errors - bad state

HTTP status code: 400 Bad Request
Error message:

If instance is active:

Instance is ACTIVE at SOME_LOCATION. It cannot be created again.

If instance is other than active state:

Instance has state STATE at SOME_LOCATION. It cannot be created.

Possible cause: Calling this API when an instance is already present or being created at some location.
Solution: Ignore the error if this API is triggered by mistake. If it is a legitimate call and you indeed want to create an instance at this location, call DeleteInstance first, at the current instance location.

Get instance

This section describes how to get details (region, state, etc.) about the API hub Runtime Instance associated with your project.

Sample request

curl https://$HOST/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/instances/default \
  -X GET \
  -H "Authorization: Bearer $TOKEN"

Sample response - instance creation in progress

{
  "name": "projects/my-project/locations/us-central1/instances/default",
  "createTime": "2022-03-11T08:32:14.944703257Z",
  "updateTime": "2022-03-11T08:32:14.944703257Z",
  "state": "CREATING",
  "stateMessage": "Creating instance...\nDetails: projects/PROJECT_ID/locations/RUNTIME_LOCATION/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "config": {
    "location": "us-central1",
    "cmekKeyName": "projects/PROJECT/locations/RUNTIME_LOCATION/keyRings/KEYRING/cryptoKeys/KEY"
  }
}

Sample response - instance creation complete

{
  "name": "projects/myproject/locations/us-central1/instances/default",
  "createTime": "2022-03-11T08:32:14.944703257Z",
  "updateTime": "2022-03-11T08:56:31.087709218Z",
  "config": {
    "location": "us-central1",
    "cmekKeyName": "projects/my-project/locations/us-central1/keyRings/apihub-key-ring/cryptoKeys/apihub-key"
  },
  "state": "ACTIVE",
  "stateMessage": "Instance is active and ready to use."
}

Common errors

HTTP status code: 404 Not Found
Error message: Resource was not found.
Possible cause: Calling this API at a location where an instance does not exist.
Solution: Call the CreateInstance API before calling the GetInstance API at the location where you want to create the Instance. If the Instance has been created but you don't know the location, call CreateInstance API at any location, which fails with a message that provides a hint on the Instance location.

Delete instance

This section describes how to delete an instance.

Sample request

curl https://$HOST/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/instances/default \
  -X DELETE \
  -H "Authorization: Bearer $TOKEN"

Sample response

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "delete",
    "apiVersion": "v1"
  },
  "done": false
}

Common errors

HTTP status code: 404 Not Found
Error message: Resource was not found.
Possible cause: Calling this API at a location where an instance does not exist.
Solution: Call DeleteInstance only at the location where instance is ACTIVE or FAILED.
HTTP status code: 400 Bad Request
Error message: Instance must be ACTIVE or FAILED to be deleted. Current state: STATE.
Possible cause: Calling this API at a location where the instance state is not ACTIVE or FAILED.
Solution: Call DeleteInstance only at the location where instance is ACTIVE or FAILED.

Get operation

This section describes how to check the operation status. When operations take a long time to complete (LROs), the API returns an operation ID. Calling GetOperation using the operation ID returns the operation status.

Sample request

curl https://$HOST/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/operations/OPERATION_ID \
  -X GET \
  -H "Authorization: Bearer $TOKEN"

Where OPERATION_ID is a value returned for LROs as explained in Create instance, and is in the form operation-1650479361714-5dd1a2c1068bf-464fac6b-18eeb734.

Sample response - instance creation in progress

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": false
}

Sample response - instance creation complete

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "endTime": "2022-03-11T08:56:31.069701960Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.Instance",
    "name": "projects/my-project/locations/us-central1/instances/default",
    "createTime": "2022-03-11T08:32:14.944703257Z",
    "updateTime": "2022-03-11T08:56:31.069701960Z",
    "config": {
      "location": "us-central1",
      "cmekKeyName": ""projects/PROJECT/locations/RUNTIME_LOCATION/keyRings/KEYRING/cryptoKeys/KEY""
    },
    "state": "ACTIVE",
    "stateMessage": "Instance is active and ready to use."
  }
}

Sample response - instance deletion complete

{
  "name": "projects/my-project/locations/us-east1/operations/operation-1647669637561-5da8bfb743b86-4af586a4-83c04472",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-19T06:00:38.046462309Z",
    "endTime": "2022-03-19T06:01:01.382751041Z",
    "target": "projects/my-project/locations/us-east1/instances/default",
    "verb": "delete",
    "apiVersion": "v1"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.protobuf.Empty"
  }
}

What's next