TT Lab
Get started
Learn Learning paths Courses

ICA — Istio Certified Associate

ICA Mock Exam A

Continue in TT Lab

This is ICA Mock Exam A. The time limit is 120 minutes, there are 17 tasks, and the passing line is 68%. Scoring is partial, so it is better to skip a task you get stuck on and come back to it later.

Because this is a mock exam, do not look at hints or answers; try to finish it all first. Not solving something because you ran out of time and not solving it because you did not know it are different problems, and you must distinguish the two to decide what to study next. Open them only after you have solved everything and graded.

The real exam environment

During the exam you can view istio.io/docs, istio.io/blog, and kubernetes.io/docs. Searching inside the documentation site with istio.io/search/ is allowed, but you must not click external search results. The k alias, bash completion, and istioctl completion are already set up. You work by using ssh to the host specified for each task, and nested ssh is not supported. Copying in the terminal is Ctrl+Shift+C, and pasting is Ctrl+Shift+V.

This mock exam environment

You work directly in a single-user cluster inside the Pod (ssh is not needed). The kube-apiserver is real, so an incorrect manifest is actually rejected, but sidecars do not come up and traffic does not flow. Grading works by re-reading the configuration you left on the cluster.

Task 1 is the premise for most of the rest. Until the Istio resource kinds are registered, kubectl apply will not accept a VirtualService. Finish it first.


1. Generate the Istio installation manifest for the default profile and save it to /root/ica/install/manifest.yaml. Then pick out only the CustomResourceDefinition objects in that manifest and register them in the cluster. Since the istiod Pod does not come up in this environment, all you need are the API types.

2. Create three namespaces and attach the sidecar injection labels.

3. Reverse the namespace's decision at the Pod level. Both Deployments have 1 replica and the image nginx:1.27-alpine.

4. In ica-shop, bring up the reviews service in three versions and define the subsets.

5. Create a VirtualService reviews in ica-shop. The host is reviews.ica-shop.svc.cluster.local, and with a single rule with no conditions, split 80 to subset v1 and 20 to subset v2.

6. Add two more rules in front of the VirtualService reviews from task 5 to make three in all. The order is what is graded.

  1. If the header end-user is exactly tester, subset v3
  2. If the uri prefix is /api/v2 and at the same time the method is GET, subset v2
  3. The weighted rule from task 5 remains as the last rule with no conditions

7. Attach resilience settings to the last (no-condition) rule of the same VirtualService reviews. The overall timeout is 2s, 3 retries, a per-try timeout of 500ms, and the retry conditions are 5xx, reset, and connect-failure.

8. Add limits and outlier detection to the trafficPolicy of the DestinationRule reviews.

9. Set up ingress in ica-shop.

10. Enforce mTLS mesh-wide but make only the outdated namespace an exception.

11. Raise only the legacy-api workload in ica-legacy to STRICT, but make port 8080 an exception. The PeerAuthentication name is legacy-api, the selector is app: legacy-api, mtls.mode is STRICT, and 8080 in portLevelMtls is DISABLE.

12. Create two authorization policies in ica-shop. Both have the selector app: reviews.

13. Attach JWT verification to the app: reviews workload in ica-shop.

14. A team said it would write to the ica-fix namespace and handed over only the VirtualService below. As it stands, istioctl analyze reports errors. Diagnose what is missing and fill it in, and make istioctl analyze -n ica-fix report no Errors at all.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: payments
  namespace: ica-fix
spec:
  hosts:
    - payments.ica-fix.svc.cluster.local
  http:
    - route:
        - destination:
            host: payments.ica-fix.svc.cluster.local
            subset: stable

The specification of what to fill in is this. The Deployment payments has the Pod labels app=payments and version=v1, the Service payments has port 9090 with the port name http, and the DestinationRule payments uses the same FQDN as above as its host and defines the subset stable as version: v1. Do not leave resources unrelated to the task in this namespace. If any remain, analyze catches those too.

15. After applying the VirtualService below in the ica-triage namespace, traffic always goes to stable even when the x-beta: true header is attached. Diagnose the cause and apply your fix. Keep the two rules as they are.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: checkout
  namespace: ica-triage
spec:
  hosts:
    - checkout.ica-triage.svc.cluster.local
  http:
    - route:
        - destination:
            host: checkout.ica-triage.svc.cluster.local
            subset: stable
    - match:
        - headers:
            x-beta:
              exact: "true"
      route:
        - destination:
            host: checkout.ica-triage.svc.cluster.local
            subset: beta

16. After putting in the policy below, the payments workload in ica-triage rejects every request. Diagnose the cause and fix it so that only cluster.local/ns/ica-triage/sa/frontend accessing /pay* with POST is allowed.

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: payments-allow
  namespace: ica-triage
spec:
  selector:
    matchLabels:
      app: payments
  action: ALLOW
  rules: []

17. After putting the two resources below in ica-triage, every caller of orders fails. Leave the server-side requirement as it is and fix the client side.

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: ica-triage
spec:
  mtls:
    mode: STRICT
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: orders
  namespace: ica-triage
spec:
  host: orders.ica-triage.svc.cluster.local
  trafficPolicy:
    tls:
      mode: DISABLE

For tasks 15 to 17, there is no need to create workloads in ica-triage. What you must fix is the configuration.

Registering the mesh API types in the cluster

istioctl manifest generate carries the charts inside the binary and works without the internet. Its result even includes istiod and the services, but all you need in this environment is the CRDs, so filter them out by kind. When applying, use --server-side. Istio CRDs have large annotations and exceed the last-applied-configuration limit (262144 bytes) of a regular apply.

Attaching sidecar injection labels per namespace

If a revision label and the istio-injection label are on a namespace together, istio-injection wins. So if you do not remove the old label while moving to a revision, the new revision is silently ignored. To remove it, add a minus sign after the label name.

Reversing injection at the Pod level

sidecar.istio.io/inject goes on the label of the Pod template. It is not a label or annotation of the Deployment itself. The value must be a string wrapped in quotes. Kubernetes label values accept only strings, so if you write it without quotes, the apiserver rejects it.

Creating per-version workloads and subsets

If you put version in the Service's selector, only one version is caught and weighted distribution becomes impossible altogether. Splitting versions is the job of the DestinationRule's subsets. A subset's labels must be literally the same as the Pod labels, not the subset name, and write spec.host as an FQDN instead of a short name. The service port name is the basis on which Istio determines the protocol.

Splitting 80 to 20 by weight

Weights attach to each destination in the route array and must sum to 100. Do not put a match in this rule. In the later tasks, rules with conditions come in front of this one, and the rule with no conditions must always be at the very end.

Putting specific rules in front of the catch-all

Rules are evaluated from top to bottom and the first match wins. If the rule with no conditions is at the very front, the rules behind it are never evaluated. And to combine two conditions with AND, you must write them side by side inside the same match block. If you split them into two blocks, it becomes OR.

Matching the relationship between timeout and retries

timeout is the overall deadline including retries. If perTryTimeout times the number of attempts exceeds timeout, the last attempt is cut off before it even starts. Here 500ms times 3 is 1.5 seconds, which fits within 2 seconds. retryOn is a string joined with commas, and if you leave it empty, which failures to retry on is not determined.

Applying connection pool limits and outlier detection

The two are inside the same trafficPolicy but do different things. connectionPool restrains the load going out from this side, and outlierDetection temporarily removes an instance on the other side if it keeps giving 5xx. If you do not write maxEjectionPercent, the field is not stored at all, so state the value explicitly. Be careful not to delete the loadBalancer you created in an earlier task.

Setting up the ingress gateway

A Gateway only opens ports and does not do routing. If you do not attach a VirtualService by writing the name in its spec.gateways, that rule applies only inside the mesh and external requests get a 404. httpsRedirect goes under the tls of the port 80 server. The certificate is looked up by credentialName in the gateway Pod's namespace.

Mesh-wide STRICT and a namespace exception

PeerAuthentication applies in three layers. If there is no selector and it is in the root namespace (istio-system), it is mesh-wide; if there is no selector and it is in another namespace, it is that entire namespace; and if there is a selector, it is a workload. The narrower scope wins over the wider. The moment you attach a selector to the global policy, it is no longer global.

Putting a port exception on a workload STRICT

portLevelMtls works only in a workload policy that has a selector. If you use it without a selector, the apiserver rejects it. And the port number you write here is not the Service port but the Pod's container port. If you write the Service port, the exception hooks onto nothing, and that fact passes quietly without an error.

Using ALLOW and DENY policies separately

DENY is evaluated before ALLOW, and if even one matches, it ends there. The evaluation order is CUSTOM, DENY, ALLOW. A principal is a service account's SPIFFE identity and its format is cluster.local/ns/<네임스페이스>/sa/<서비스계정> (the placeholders are the namespace and the service account). An asterisk at the end of a path is a prefix match.

Applying JWT verification and a token requirement together

RequestAuthentication only verifies a token if there is one, and lets a request without a token just pass. To require a token, you must also apply an AuthorizationPolicy that uses requestPrincipals. The format of requestPrincipals is the issuer and the subject joined with a slash, and to restrict only the issuer, put an asterisk after it.

Filling in what analyze catches

Run istioctl analyze -n ica-fix first and read what it says it cannot find. IST0101 means it could not find the referenced host or the pairing of host and subset. The same code appears whether the Service is missing or the DestinationRule lacks that subset. If you fill in one at a time and run it again, you can see what remains shrinking.

Reviving an unreachable rule

Rules are evaluated from top to bottom and the first match wins. A rule with no conditions matches every request, so if it is at the very front, the rules behind it are not evaluated for any request. No error appears and the configuration stays valid, so you have no choice but to find it by eye.

Fixing an empty ALLOW policy that blocks every request

If even one AuthorizationPolicy applies to a workload, that workload turns to default deny. In that state, if the ALLOW rules are empty, no request can match a rule and all are denied. No policy and an empty policy produce opposite results.

Fixing client TLS that conflicts with the server requirement

PeerAuthentication decides what the server will accept, and the DestinationRule's trafficPolicy.tls decides how the client connects. If the server is STRICT but the client is DISABLE, it connects in plaintext and is cut off. Both are valid configurations, so neither gives an error, which is what makes this outage hard. Choose the mode in which the sidecar handles the certificates for you.