Declarative configuration import for Istio gateways, clients, policies, and APIs
For ACP deployment agents can import and declaratively configure gateways, client applications, policies, and APIs. Learn how to utilize the built-in importJob to speed up your workflow and provide access control for your APIs.
About configuration import
In addition to ACP’s import APIs,
it is possible to configure your ACP deployment declaratively using the
built-in importJob
. The configuration import can be used for all ACP
deployment types including the ACP SaaS deployment or ACP
deployment on kubernetes.
You can define client applications, gateways (both for multi-tenant and single-tenant authorizers), policies, and APIs.
Declarative configuration import allows you to use the GitOps approach where you store your configuration inside your Git repository and have your configuration and infrastructure as code. In this case, your Git repository acts as a single source of truth for your gateways and services configuration. This leads to increased productivity for your teams, enhanced developer experience, improved stability and reliability, consistency, and many more.
You can create multiple import jobs with different responsibilities for each job. You can, for example, prepare one job that creates an Istio Authorizer with its client application, and multiple different import jobs that are responsible for your services/APIs import and their protection.
Any integration with the DevSecOps pipelines is made easier with the declarative configuration import. As with this approach, the import job can be executed in a satellite environment that communicates with ACP using the import API protected by the System tenant credentials.
importJob configuration example
In the example below, you can see the importJob
definition that is responsible for importing an
Istio Authorizer to a default tenant and a client application for this authorizer in the system
workspace for the default tenant.
apiVersion: batch/v1
kind: Job
metadata:
name: acp-import-job
namespace: acp-system
spec:
backoffLimit: 4
template:
spec:
imagePullSecrets:
- name: docker.cloudentity.io
volumes:
- name: import
configMap:
name: acp-import
containers:
- name: acp-import
image: "docker.cloudentity.io/acp:{version}"
imagePullPolicy: IfNotPresent
args:
- import
- --client-id
- "$(CLIENT_ID)"
- --client-secret
- "$(CLIENT_SECRET)"
- --issuer-url
- "$(ISSUER_URL)"
- --mode
- update
- --format
- yaml
- --input
- /import/seed.yaml
env:
- name: CLIENT_ID
valueFrom:
secretKeyRef:
name: import-job-secrets
key: IMPORT_JOB_CLIENT_ID
- name: CLIENT_SECRET
valueFrom:
secretKeyRef:
name: import-job-secrets
key: IMPORT_JOB_CLIENT_SECRET
- name: ISSUER_URL
valueFrom:
secretKeyRef:
name: import-job-secrets
key: ISSUER_URL
volumeMounts:
- mountPath: /import
name: import
readOnly: true
restartPolicy: Never
---
apiVersion: v1
kind: ConfigMap
metadata:
name: acp-import
namespace: acp-system
data:
seed.yaml: |
clients:
- tenant_id: {tid}
authorization_server_id: {aid}
client_id: {client_id}
client_secret: {client_secret}
client_name: sample gateway
token_endpoint_auth_method: client_secret_basic
grant_types:
- client_credentials
scopes:
- read_gateway_configuration
- write_gateway_configuration
- push_gateway_requests
- introspect_tokens
gateways:
- tenant_id: {tid}
authorization_server_id: {aid}
id: local_istio_gateway
name: Sample Istio Gateway
type: istio
client_id: {client_id}
Prerequisites
-
Access to the ACP tenant and its System workspace.
System workspace access
The
importJob
results in a call to ACP’s import configuration API that is protected by System workspace credentials. System workspace access, by default, is hidden behind a feature flag. If you need access to the System workspace for your tenant, contact Cloudentity Sales team. -
Client application created in the System workspace.
Client configuration
To be able to import the defined configuration, your import job needs to be able to authenticate to ACP by calling the ACP OAuth 2.0 token endpoint. Therefore, you need to allow the client credentials OAuth grant flow for your client application and assign the
manage_configuration
scope to it. To learn more about creating clients used for calling ACP’s APIs, see the Getting started with ACP REST API -
kubernetes cluster up and running.
For the purpose of this article, the acp-on-k8s environment is used that allows you to rapidly stand up your ACP instance in your local development environment. For prerequisites and references for this deployment, visit a dedicated acp-on-k8s GitHub repository.
-
Istio Gateway deployed in your kubernetes cluster.
-
Service of your choice deployed in your kubernetes cluster.
You need to deploy a service in order to be able to import APIs to your ACP instance and apply access control to protect them.
Tip
If you do not have a deployment-ready service at hand, you can deploy, for example, a httpbin service which can be found in the acp-on-k8s GitHub repository.
Configuration files
This article is based on custom deployment configuration files. For default files and more examples, check the acp-on-k8s GitHub repository.
Configure Istio Authorizer
-
In a directory of your choice, create a
kustomization.yaml
file.As
kubectl
supports managing objects using Kustomize, it is possible to generate kubernetes Secrets and ConfigMaps. In this case, thekustomization.yaml
file is responsible for storing the secrets and other data crucial for configuring your Istio Authorizer.Example:
resources: - register-gateway.yaml - manifest.yaml secretGenerator: - name: istio-authorizer-secrets namespace: acp-system literals: - CLIENT_ID={your_client_id} - CLIENT_SECRET={your_client_secret} - ISSUER_URL=https://{tid}.us.authz.cloudentity.io/{tid}/system - name: import-job-secrets namespace: acp-system literals: - ISSUER_URL=https://{tid}.us.authz.cloudentity.io/{tid}/system - IMPORT_JOB_CLIENT_ID={IMPORT_JOB_CLIENT_ID} - IMPORT_JOB_CLIENT_SECRET={IMPORT_JOB_CLIENT_SECRET}
The
resources
objects point to files that define your Istio Authorizer configuration. You will create both files in the next steps.With the kubernetes
secretGenerator
you can create kubernetes Secrets, in this case,istio_authorizer_secrets
andimport_job_secrets
that can store literals.For the
istio-authorizer-secrets
object define the following literals:-
CLIENT_ID
which value should be set for your Istio Authorizer client identifier. -
CLIENT_SECRET
which value should be set for your Istio Authorizer client secret. -
ISSUER_URL
which value must point to the issuer URL of the System workspace of your tenant.
Issuer URL
Your issuer URL always follow the format:
https://{tid}.us.authz.cloudentity.io/{tid}/system
where{tid}
stands for your tenant identifier.For the
import-job-secrets
Secret define the following literals:-
IMPORT_JOB_CLIENT_ID
value must point to the client identifier of the client application that you have created in the System workspace for your tenant. -
IMPORT_JOB_CLIENT_SECRET
value must point to the client secret of the client application that you have created in the System workspace for your tenant. -
ISSUER_URL
which value must point to the issuer URL of the System workspace of your tenant.
Issuer URL
Your issuer URL always follow the format:
https://{tid}.us.authz.cloudentity.io/{tid}/system
where{tid}
stands for your tenant identifier.Both the
IMPORT_JOB_CLIENT_SECRET
and theIMPORT_JOB_CLIENT_ID
parameter are passed to the ACP OAuth 2.0 token endpoint in the client credentials grant flow to authenticate the client application that requests your configuration import for your authorizer.Security recommendation
To increase security of secrets stored in your repository, it is recommended to encrypt your kubernetes secrets. You can use tools like Mozilla SOPS or Bitnami Sealed Secrets to encrypt your secrets.
When the secrets are applied to your kubernetes deployment, the secrets are encrypted and visible as plain text. Anyone who is authorized to create a Pod in a namespace can read any secret in that namespace; this includes indirect access such as the ability to create a Deployment. To mitigate the risks, kubernetes recommends to:
-
Enable encryption at Rest for secrets.
-
Enable or configure RBAC rules that restrict reading data in secrets.
-
Where appropriate, use mechanisms such as RBAC to limit which principals are allowed to create or replace secrets.
To learn more, visit kubernetes secrets documentation
-
-
In a directory of your choice, create a
manifest.yaml
file and provide a definition for your Istio Authorizer instance. See an example below.apiVersion: v1 kind: Namespace metadata: name: acp-system --- apiVersion: v1 kind: ServiceAccount imagePullSecrets: - name: docker.cloudentity.io metadata: name: istio-authorizer namespace: acp-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: istio-authorizer namespace: acp-system roleRef: apiGroup: "" kind: ClusterRole name: istio-authorizer subjects: - kind: ServiceAccount name: istio-authorizer namespace: acp-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: istio-authorizer-auth-delegator namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:auth-delegator subjects: - kind: ServiceAccount name: istio-authorizer namespace: acp-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: istio-authorizer namespace: acp-system rules: - apiGroups: - "apps" resources: - "deployments" verbs: - "list" --- apiVersion: v1 kind: ConfigMap metadata: name: istio-authorizer-data namespace: acp-system data: ca.pem: | -----BEGIN CERTIFICATE----- MIIDfjCCAmagAwIBAgIUHOLlcMhX8uJyFafYYNXYBMBJr2swDQYJKoZIhvcNAQEL BQAwVzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT B1NlYXR0bGUxFDASBgNVBAoTC0Nsb3VkZW50aXR5MQswCQYDVQQLEwJDQTAeFw0y MTAxMjAwOTQ4MDBaFw0yNjAxMTkwOTQ4MDBaMFcxCzAJBgNVBAYTAlVTMRMwEQYD VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRQwEgYDVQQKEwtDbG91 ZGVudGl0eTELMAkGA1UECxMCQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDKJroMoumr9jY129z7uf0WrvMxmzexP72ogINlQlM/p910YfnLYSWOUEIH kQ5eyq3ATuesPzamNxjq4JkafopsMBeieCeVzir4VTmsxLxbBZG2GjdsGpyXmrXb LXTb5dgNcolYh6LLPb11cBeb9TAy2D97Vx4t1Hr2SeLG1VvkNyNnoog6tZdmJUis ufW9GOyXgiAv46rtgvvpzYn+LbE7oiXlQHICHNpeTh7140HG7eWMPubINuilGZBY W80IGTpGUf2Vmuwo2LA17z5/3IB0dqlY5eT321TYVoqH1TYZrMllSLc+2x750e+l E9sHil8QPptAS74UWUsq2PgIvyZbAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTKWQeEZBRJ/UO1Py7EfTaOqVujbTAN BgkqhkiG9w0BAQsFAAOCAQEAsg5ker9FPcq1u5E+y4Qq1yjUeuOT0kap+aIE1mp2 LSQoEA+tb40s/iNmTMdvCGReeoRoVYKz66+3zGoFYg5W1c5Ct9whjiLhKP1Pzc4I JbPGklSrnnAwD72ypLF4yrTMTD65gTMsr2ao0MOe6vy/Z8R2uz48QJHhhi71VGhi FstSiWvb4AgNhN39Ag5ufLtrGCbuZw5TSeW0J7PTBoYV1Z/0jrsdqxk8MjnbR8Qe VyZGyIRnGkXUtC239/Lz0v0PXVwAPUF8ITb0JYcG/ojIc5VfTOkQOeOHHBaS+dXt HBJjBbnwpN4tNFhczJkbga16hL+vV0I4z61mJG8OkDr25Q== -----END CERTIFICATE----- --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: istio-authorizer namespace: acp-system name: istio-authorizer spec: replicas: 1 selector: matchLabels: app: istio-authorizer template: metadata: labels: app: istio-authorizer name: istio-authorizer spec: serviceAccountName: istio-authorizer containers: - image: docker.cloudentity.io/istio-authorizer:latest imagePullPolicy: IfNotPresent name: istio-authorizer args: - --client-id - "$(CLIENT_ID)" - --client-secret - "$(CLIENT_SECRET)" - --issuer-url - "$(ISSUER_URL)" - --disable-service-discovery - "true" - --root-ca - /data/ca.pem env: - name: LOGGING_LEVEL value: "INFO" - name: CLIENT_ID valueFrom: secretKeyRef: name: istio-authorizer-secrets key: CLIENT_ID - name: CLIENT_SECRET valueFrom: secretKeyRef: name: istio-authorizer-secrets key: CLIENT_SECRET - name: ISSUER_URL valueFrom: secretKeyRef: name: istio-authorizer-secrets key: ISSUER_URL volumeMounts: - mountPath: /data name: data ports: - containerPort: 9001 readinessProbe: tcpSocket: port: 9001 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: tcpSocket: port: 9001 initialDelaySeconds: 15 periodSeconds: 20 volumes: - name: data configMap: name: istio-authorizer-data --- apiVersion: v1 kind: Service metadata: name: istio-authorizer namespace: acp-system labels: app: istio-authorizer spec: ports: - port: 9001 name: grpc - port: 9002 name: http selector: app: istio-authorizer
The example above is responsible for the following steps in your deployment:
-
It defines the namespace (
acp-system
) where your Istio Authorizer is to be deployed. -
It defines a kubernetes service account for your pod with the authorizer.
-
It provides three kubernetes cluster role bindings that are responsible for granting permissions across your whole kubernetes cluster.
-
It defines a cluster role for your kubernetes cluster. It is used to grant access to secrets in your
acp-system
namespace. -
It provides a
ConfigMap
for your Istio Authorizer that contains the certificate of your authorizer used for TLS authentication. -
It provides deployment configuration for your Istio Authorizer instance.
In the deployment configuration, you can see that the
istio-authorizer
specification contains the latest Istio Authorizers docker image. It also provides the following deployment arguments:-
--client-id
which value points to theCLIENT_ID
environment variable that stores the client identifier of the Istio Authorizer’s client which you have provided in thekustomization.yaml
file. -
--client-secret
which value points to theCLIENT_SECRET
environment variable that stores the client secret of the Istio Authorizer’s client you have provided in thekustomization.yaml
file. -
--issuer-url
which value points to theISSUER_URL
environment variable that stores the issuer URL of the Istio Authorizer’s client you have provided in thekustomization.yaml
file. -
--disable-service-discovery
flag set totrue
. If enabled, the automatic service discovery is disabled for your Istio Authorizer instance. This causes that your services and APIs are not automatically imported to ACP and you can declaratively import them using theimportJob
. -
--root-ca
which stores the path to the TLS certificate for your Istio Authorizer.
In the
deployment
configuration, environment variables are also defined for your Istio Authorizer’s kubernetes deployment. The variables are used, for example, to define the values for the arguments listed above.volumeMounts
are a part of thedeployment
configuration that is responsible for mounting of the declared volume into a container within the same pod. In the code snippet above, you can see that adata
volume is defined and also mounted using thevolumeMounts
so that it exists within the same pod as the Istio Authorizer’s deployment. -
-
The
manifest.yaml
file also provides a definition for the Istio Authorizer’s service and ports mapping that are used to enable either the gRPC or the HTTP services deployment and protection.
-
Define import job and gateway configuration
In a directory of your choice, create a register-gateway.yaml
file that is to be responsible for
providing configuration for your import job and for providing actual ACP
configuration to be imported.
Configure import job
The first part of the register-gateway.yaml
file, should be the definition of your import
job. See an example below:
apiVersion: batch/v1
kind: Job
metadata:
name: acp-import-job
namespace: acp-system
spec:
backoffLimit: 4
template:
spec:
imagePullSecrets:
- name: docker.cloudentity.io
volumes:
- name: import
configMap:
name: acp-import
containers:
- name: acp-import
image: "docker.cloudentity.io/acp:1.14.1"
imagePullPolicy: IfNotPresent
args:
- import
- --client-id
- "$(CLIENT_ID)"
- --client-secret
- "$(CLIENT_SECRET)"
- --issuer-url
- "$(ISSUER_URL)"
- --mode
- update
- --format
- yaml
- --input
- /import/seed.yaml
env:
- name: CLIENT_ID
valueFrom:
secretKeyRef:
name: import-job-secrets
key: IMPORT_JOB_CLIENT_ID
- name: CLIENT_SECRET
valueFrom:
secretKeyRef:
name: import-job-secrets
key: IMPORT_JOB_CLIENT_SECRET
- name: ISSUER_URL
valueFrom:
secretKeyRef:
name: import-job-secrets
key: ISSUER_URL
volumeMounts:
- mountPath: /import
name: import
readOnly: true
restartPolicy: Never
---
The acp-import-job
is a kubernetes job
that is responsible for creating a pod and retrying the execution of the import job pod
until it successfully terminates. The backoffLimit
is set to 4
so after four import
failures, your pod my reach the CrashLoopBackoff
limit error. This may mean that you have
an error in the configuration that you are trying to import.
As with the manifest.yaml
file, you can see that for your job definition the same arguments
and environment variables are set. Additionally, you can see that the --mode
argument set
to update
is used. This argument is responsible for defining what happens in a case when
there are any configuration conflicts when you are trying to import your configuration. To
know more about the --mode
argument and possible values, see
the insert mode documentation.
The job definition also contains the --format
argument which, contrary to a standard API
call to ACP’s import/export tenant configuration APIs, accepts YAML
input for your configuration. Additionally, the --input
argument is added which is
responsible for providing a path to your imported configuration that residues on your
kubernetes pod.
Provide configuration for gateway and its client
The second part of the register-gateway.yaml
file should provide a ConfigMap
for your
imported data. See an example below:
apiVersion: v1
kind: ConfigMap
metadata:
name: acp-import
namespace: acp-system
data:
seed.yaml: |
clients:
- tenant_id: {tid}
authorization_server_id: system
client_id: {your_gateway_client_id}
client_secret: {client_secret}
client_name: My Local Gateway
token_endpoint_auth_method: client_secret_basic
grant_types:
- client_credentials
scopes:
- read_gateway_configuration
- write_gateway_configuration
- push_gateway_requests
- introspect_tokens
gateways:
- tenant_id: {tid}
authorization_server_id: {aid}
id: {gateway_id}
name: Sample Istio Gateway import
type: istio
client_id: {your_gateway_client_id}
The above example imports an Istio Gateway (Authorizer) to a default workspace of a default tenant.
The configuration of the gateway also contains a reference to the client_id
({your_gateway_client_id}
) of the client application that is also imported.
Gateway object
In ACP, a gateway object consists of two entities: actual gateway (authorizer) and a client application created for that gateway (authorizer) in the System workspace of the tenant where the gateway is created. In ACP application, whenever you create a gateway in your tenant, a client application is automatically created for you in your tenant’s System workspace. This is why, while importing a gateway, you must also import a client application for your gateway.
For client applications that are created for authorizers, the following scopes must be assigned:
introspect_tokens
, push_gateway_requests
, read_gateway_configuration
, and
write_gateway_configuration
.
Deploy Istio Authorizer
After defining your Istio Authorizers deployment configuration, you need to deploy it to your cluster. Depending on your deployment configuration, you can do it, for example, in the following ways:
-
using the kubectl apply command, for example:
-
kubectl apply -f {FILENAME}
to apply a single file where{FILENAME}
is the file you want to apply. -
kubectl apply -k {DIRECTORY}
to apply a directory with all the files it contains. Replace the{DIRECTORY}
variable with a directory where you have all your configuration files that you have prepared so far.
-
-
using the kubectl kustomize command, for example
kubectl kustomize {DIRECTORY}
where the{DIRECTORY}
is a variable that references the directory where you have yourkustomization.yaml
file and other resources.
By running kubectl get pods -A
you are able to get all pods from all namespaces running on your
kubernetes cluster. The list should contain two pods similar to the following:
$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
acp-system acp-import-job-frpj6 0/1 Completed 0 48m
acp-system istio-authorizer-69fbdddf48-8ngjq 1/1 Running 1 48m
You can see that the list contains two pods running in the acp-system
namespace, one being the
acp-import-job-xyz
responsible for the import job, and the second responsible for your Istio
Authorizer’s deployment (istio-authorizer-xyz
). You can see the logs of your authorizer by
executing the following kubectl logs $pod -n $namespace
. If you were to run this command for the
pods from the codeblock above (kubectl logs istio-authorizer-69fbdddf48-8ngjq -n acp-system
) you
would see the output similar to the following:
{"level":"info","msg":"Starting authorizer reload...","time":"2021-10-22T09:30:11Z"}
{"level":"info","msg":"Authorization configuration reloaded (948.300757ms)","time":"2021-10-22T09:30:12Z"}
If you have the service discovery enabled (--disable-service-discovery
set to false in your
manifest.yaml
file), at this point, you should be able to see your APIs and
services in your ACP tenant.
Quick summary
Let’s quickly recap what you have achieved so far:
-
You have prepared your Istio Authorizer’s deployment configuration that consists of three files:
-
kustomization.yaml
that defines the resources for your Istio Authorizer’s deployment and is responsible for generating kubernetes Secrets. -
manifest.yaml
that provides configuration for your Istio Authorizer’s deployment. -
register-gateway.yaml
that is responsible for providing the import kubernetes job and data that is going to be imported to your ACP tenant.
-
-
You have deployed your configuration files.
In your ACP tenant, in a workspace that you have specified in the
register-gateway.yaml
file, you should see your Istio Authorizer that you have imported. Go to
your workspace > APIs > Gateways if you wish to confirm it.
In the System workspace for your ACP tenant, you should be able to see a client application for your Istio Authorizer. It has the same client identifier as the Istio Authorizer instance that you have imported. Go to System workspace > Applications if you wish to confirm it.
In general, you have done the groundwork that allows you to protect your APIs. Once you have your Istio Authorizer integrated with ACP, you can proceed to the next steps. You will prepare a deployment of your import job that is to be responsible for importing policies, services, APIs, and assigning your authorization policies to those imported APIs. This way, you can have your policies, services, and APIs definition completely separate from your Istio Authorizer’s deployment.
Configure import job for policies, services, and APIs
To be able to declaratively configure your policies, services, and APIs, you need to perform the following steps:
-
Connect an Istio Authorization policy to your Istio Gateway.
Istio allows externalized authorization decisioning. In order to get your Istio Authorizer integrated with an Istio Gateway, you need to create an [Istio Authorization policy] that delegates the authorization decisioning and access control to Istio Authorizer and ACP.
-
Prepare a kubernetes
kustomization.yaml
file that is responsible for generating the secrets for your import job and providing resources files for your deployment. -
Prepare your import job deployment and the imported configuration.
Your import job is going to be executed in a separate pod. You can create multiple different import jobs that are responsible for importing different sets of policies, services, and APIs.
Define kustomization
In a directory of your choice prepare a kustomization.yaml
file that is responsible for generating
the secrets for your import job and providing resources files for your deployment. See example
below:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- protect-apis.yaml
- istio-policy.yaml
secretGenerator:
- name: import-job-secrets
namespace: acp-system
literals:
- ISSUER_URL=https://<tenantid>.us.authz.cloudentity.io/<tenantid>/system
- IMPORT_JOB_CLIENT_ID={IMPORT_JOB_CLIENT_ID}
- IMPORT_JOB_CLIENT_SECRET={IMPORT_JOB_CLIENT_SECRET}
The first part of your kustomization.yaml
file is responsible for providing a resources
object
that points to files that define your deployment configuration. You will create those files in the
next steps.
With the kubernetes secretGenerator
you can create kubernetes Secrets, in this case,
import_job_secrets
that can store literals for your deployment.
For the import-job-secrets
Secret define the following literals:
ISSUER_URL
which value must point to the issuer URL of the System workspace of your tenant.
Issuer URL
Your issuer URL always follow the format:
https://{tid}.us.authz.cloudentity.io/{tid}/system
where{tid}
stands for your tenant identifier.
-
IMPORT_JOB_CLIENT_ID
value must point to the client identifier of the client application that you have created in the System workspace for your tenant. -
IMPORT_JOB_CLIENT_SECRET
value must point to the client secret of the client application that you have created in the System workspace for your tenant.
Both the IMPORT_JOB_CLIENT_SECRET
and the IMPORT_JOB_CLIENT_ID
parameter are used as the part
of the client credentials grant flow call to the ACP OAuth 2.0 token endpoint
to authenticate the client application that requests your policies, services, and APIs import for
your tenant.
Security recommendation
To increase security of secrets stored in your repository, it is recommended to encrypt your kubernetes secrets. You can use tools like Mozilla SOPS or Bitnami Sealed Secrets to encrypt your secrets.
When the secrets are applied to your kubernetes deployment, the secrets are encrypted and visible as plain text. Anyone who is authorized to create a Pod in a namespace can read any secret in that namespace; this includes indirect access such as the ability to create a Deployment. To mitigate the risks, kubernetes recommends to:
Enable encryption at Rest for secrets.
Enable or configure RBAC rules that restrict reading data in secrets.
Where appropriate, use mechanisms such as RBAC to limit which principals are allowed to create or replace secrets.
To learn more, visit kubernetes secrets documentation
Prepare Istio authorization policy
In a directory of your choice, prepare an istio-policy.yaml
file. See example below.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: acp-authorizer
namespace: default
spec:
action: CUSTOM
provider:
name: acp-authorizer
rules:
- {}
The above Istio authorization policy
is responsible for creating a CUSTOM
access control action for APIs deployed behind the Istio
Gateway. The CUSTOM
action delegates the authorization to an external provider,
in this case, ACP.
Note
In the example above, the policy is applied to all services in the default namespace. Take a look at Authorization Policy Istio documentation if you would like to protect only a specific service.
Configure import job
In a directory of your choice, create a protect-apis.yaml
file that both configures your import
job, and provides the actual ACP configuration to be imported.
The first part of the register-gateway.yaml
file, should be the definition of your import
job. See an example below:
apiVersion: batch/v1
kind: Job
metadata:
name: acp-import-job
namespace: acp-system
spec:
backoffLimit: 4
template:
spec:
imagePullSecrets:
- name: docker.cloudentity.io
volumes:
- name: import
configMap:
name: acp-import
containers:
- name: acp-import
image: "docker.cloudentity.io/acp:1.14.1"
imagePullPolicy: IfNotPresent
args:
- import
- --client-id
- "$(CLIENT_ID)"
- --client-secret
- "$(CLIENT_SECRET)"
- --issuer-url
- "$(ISSUER_URL)"
- --mode
- update
- --format
- yaml
- --input
- /import/seed.yaml
env:
- name: CLIENT_ID
valueFrom:
secretKeyRef:
name: import-job-secrets
key: IMPORT_JOB_CLIENT_ID
- name: CLIENT_SECRET
valueFrom:
secretKeyRef:
name: import-job-secrets
key: IMPORT_JOB_CLIENT_SECRET
- name: ISSUER_URL
valueFrom:
secretKeyRef:
name: import-job-secrets
key: ISSUER_URL
volumeMounts:
- mountPath: /import
name: import
readOnly: true
restartPolicy: Never
---
The acp-import-job
is a kubernetes job
that is responsible for creating a pod and retrying the execution of the import job pod
until it successfully terminates. The backoffLimit
is set to 4
so after four import
failures, your pod my reach the CrashLoopBackoff
limit error. This may mean that you have
an error in the configuration that you are trying to import.
Your import job also contains the following arguments and environment variables:
-
--client-id
which value points to theCLIENT_ID
environment variable that stores the client identifier of the client application which you have provided in thekustomization.yaml
file. -
--client-secret
which value points to theCLIENT_SECRET
environment variable that stores the client secret of the client application you have provided in thekustomization.yaml
file. -
--issuer-url
which value points to theISSUER_URL
environment variable that stores the issuer URL of the System workspace where you have created the client application. -
--mode
argument set toupdate
.Insert mode
This argument is responsible for defining what happens in a case when there are any configuration conflicts when you are trying to import your configuration. To know more about the
--mode
argument and possible values, see the insert mode documentation. -
--format
that defines the format of your configuration import.Import configuration format
The import job, contrary to a standard API call to ACP’s import/export tenant configuration APIs, accepts YAML input for your configuration.
-
--input
argument is added which is responsible for providing a path to your imported configuration that residues on your kubernetes pod.
Additionally, your import job definition also contains the environment variables that are responsible for extracting your confidential data (like, for example, client identifiers) from kubernetes Secrets and passing their values to arguments described above.
Provide configuration input
Once the import job is defined, you can proceed to adding your configuration input that is going to be imported to your ACP tenant.
Add your configuration input (ConfigMap
) to the protect-apis.yaml
file. See example below.
Tip
If you want, you can add your configuration input to a separate file. If you do so, remember that you need to add your file to the
resources
object in thekustomization.yaml
file.
apiVersion: v1
kind: ConfigMap
metadata:
name: acp-import
namespace: acp-system
data:
seed.yaml: |
policies:
- tenant_id: {tid}
server_id: {aid}
id: block_test_policy
policy_name: block_test
language: cloudentity
type: api
validators:
- name: "false"
- tenant_id: {tid}
server_id: {aid}
id: allow_test_policy
policy_name: allow_test
language: cloudentity
type: api
validators:
- name: "true"
gateway_api_groups:
- tenant_id: {tid}
server_id: {aid}
service_id: httpbin
gateway_id: sample-istio-authorizer
name: "default/httpbin"
id: {{ encSpiffeID "spiffe://cluster.local/ns/default/sa/httpbin" }}
apis:
- method: GET
path: /deny
- method: GET
path: /anything
services:
- id: httpbin
tenant_id: {tid}
authorization_server_id: {aid}
gateway_id: sample-istio-authorizer
name: default/httpbin
apis:
- method: GET
path: /deny
can_have_policy: true
policy_id: block_test_policy
- method: GET
path: /anything
can_have_policy: true
policy_id: allow_test_policy
The imported configuration contains:
-
Cloudentity authorization policies for APIs:
-
block_test_policy
that is responsible for blocking all incoming API requests. -
allow_test_policy
that accepts all incoming API requests.
-
-
httpbin API group for your sample Istio Authorizer
API group IDs for Istio Authorizer
For Istio Authorizer, the API group identifier is a Base64 URL encoded SPIFFE ID which is built being based on the service account of the protected pod. To avoid using long and unreadable API groups identifiers, ACP supports Base64 encoding of SPIFFE IDs. You can define your API group identifier by following the format:
- id: "{{ encServiceID \"spiffe://{domain}/ns/{namespace}/sa/{service_id}" }}"
-
httpbin service for your sample Istio Authorizer
You can see that your configuration input contains very similar definitions of API groups and services. When you deploy an authorizer with service discovery enabled, it discovers API groups that you can later on assign to services. You can omit importing API groups and import just a service with APIs, but in this case, your APIs are not visible in the ACP’s UI under your gateway.
Deploy configuration changes
After defining your import job deployment configuration and the configuration that you want to import to ACP, you need to deploy it to your cluster. Depending on your deployment configuration, you can do it, for example, in the following ways:
-
using the kubectl apply command, for example:
-
kubectl apply -f {FILENAME}
to apply a single file where{FILENAME}
is the file you want to apply. -
kubectl apply -k {DIRECTORY}
to apply a directory with all the files it contains. Replace the{DIRECTORY}
variable with a directory where you have all your configuration files that you have prepared so far.
-
-
using the kubectl kustomize command, for example
kubectl kustomize {DIRECTORY}
where the{DIRECTORY}
is a variable that references the directory where you have yourkustomization.yaml
file and other resources.
By running kubectl get pods -A
you are able to get all pods from all namespaces running on your
kubernetes cluster. The list should contain should include your new import job:
$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
acp-system httpbin-protect-apis-job-8hqbm 0/1 Completed 0 3m
Deployment result
Once your configuration gets deployed to your kubernetes cluster, the following events take place:
-
Your Istio Gateway has an authorization policy assigned that is responsible for delegating access control to ACP.
-
With the
kustomize.yaml
file, your kustomization is applied and the Secrets are created. -
Your import job takes place and the configuration that you have provided is imported to your ACP tenant.
In the examples above, policies, an httpbin API group, and an httpbin service are imported to ACP. At the same time, the imported APIs are protected with the imported policies, one that allows all API requests, and the second that blocks all incoming API requests.
Check that your APIs are protected
To check if the policies were successfully imported and your APIs are protected, you need to make API requests to the endpoints that you have imported. To test it locally, execute the following commands in your terminal:
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.9/samples/sleep/sleep.yaml
export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
The commands above are responsible for creating a sleep
pod in your default namespace. Then, the
sleep
pod name is exported as an environment variable.
Then, you can enter the sleep pod’s shell by calling the kubectl exec -it $SLEEP_POD sh
command
and call your protected APIs. For the imported examples from above sections, the request would look
like the following: curl http://httpbin.default:80/deny -v
. As this API had the
block_test_policy
applied, the response to the request is a 403 unauthorized access error.
Changing the path to /anything
would result in a successful request, as the policy assigned to
this endpoint allows all requests.