|
| 1 | +# Authenticated Ingress with the Canonical Identity Platform |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +This tutorial demonstrates how to use the Canonical Identity Platform to add authentication to an Istio Ingress. |
| 6 | + |
| 7 | +## Prerequisites |
| 8 | + |
| 9 | +Before starting this tutorial, ensure you have: |
| 10 | + |
| 11 | +- Completed the [Get started with Charmed Istio service mesh](./get-started-with-the-charmed-istio-mesh.md) tutorial, which will give you a deployment of Istio and the sample Bookinfo application ingressed through an istio-ingress |
| 12 | +- Deployed the Canonical Identity Platform following [this tutorial](https://charmhub.io/topics/canonical-identity-platform/tutorials/e2e-tutorial). Specifically , you must complete [Deploy the Identity Platform](https://charmhub.io/topics/canonical-identity-platform/tutorials/e2e-tutorial#p-27742-deploy-the-identity-platform) and then [Set up a user with the built-in identity provider](https://charmhub.io/topics/canonical-identity-platform/tutorials/e2e-tutorial#p-27742-use-the-built-in-identity-provider) |
| 13 | + |
| 14 | +````{warning} |
| 15 | +Until [this issue](https://github.com/canonical/iam-bundle-integration/issues/66) is resolved, the Identity tutorial deploys an older version of [self-signed-certificates](https://github.com/canonical/self-signed-certificates-operator) that is incompatible with the [oauth2-proxy](https://github.com/canonical/oauth2-proxy-k8s-operator) charm used below. |
| 16 | +
|
| 17 | +To fix this, before doing `terraform apply` in the Identity Platform tutorial, edit the `certificates` variable in `examples/tutorial/variables.tf` to use a newer version: |
| 18 | +
|
| 19 | +``` |
| 20 | +variable "certificates" { |
| 21 | + description = "The configurations of the self-signed-certificates application." |
| 22 | + type = object({ |
| 23 | + units = optional(number, 1) |
| 24 | + trust = optional(bool, true) |
| 25 | + config = optional(map(string), {}) |
| 26 | + channel = optional(string, "1/stable") # <-- EDIT: previously "latest/stable" |
| 27 | + base = optional(string, "ubuntu@24.04") # <-- EDIT: previously "ubuntu@22.04" |
| 28 | + }) |
| 29 | + default = {} |
| 30 | +} |
| 31 | +``` |
| 32 | +
|
| 33 | +and the `traefik` variable to: |
| 34 | +
|
| 35 | +``` |
| 36 | +variable "traefik" { |
| 37 | + description = "The configurations of the Traefik application." |
| 38 | + type = object({ |
| 39 | + units = optional(number, 1) |
| 40 | + trust = optional(bool, true) |
| 41 | + config = optional(map(string), {}) |
| 42 | + channel = optional(string, "latest/edge") # <-- EDIT: previously "latest/stable" |
| 43 | + base = optional(string, "ubuntu@20.04") |
| 44 | + }) |
| 45 | + default = {} |
| 46 | +} |
| 47 | +``` |
| 48 | +
|
| 49 | +```` |
| 50 | + |
| 51 | +Applying This should yield a starting point similar to: |
| 52 | + |
| 53 | +````{dropdown} juju status --relations --model iam |
| 54 | +``` |
| 55 | +Model Controller Cloud/Region Version SLA Timestamp |
| 56 | +iam local-microk8s local-microk8s/localhost 3.6.8 unsupported 16:50:58-04:00 |
| 57 | +
|
| 58 | +SAAS Status Store URL |
| 59 | +ingress active local admin/core.ingress |
| 60 | +postgresql active local admin/core.postgresql |
| 61 | +
|
| 62 | +App Version Status Scale Charm Channel Rev Address Exposed Message |
| 63 | +hydra v2.3.0 active 1 hydra latest/stable 362 10.152.183.168 no |
| 64 | +kratos v1.3.1 active 1 kratos latest/stable 527 10.152.183.136 no |
| 65 | +login-ui 0.20.0 active 1 identity-platform-login-ui-operator latest/stable 166 10.152.183.37 no |
| 66 | +
|
| 67 | +Unit Workload Agent Address Ports Message |
| 68 | +hydra/0* active idle 10.1.253.238 |
| 69 | +kratos/0* active idle 10.1.253.245 |
| 70 | +login-ui/0* active idle 10.1.253.241 |
| 71 | +
|
| 72 | +Offer Application Charm Rev Connected Endpoint Interface Role |
| 73 | +kratos-info-offer kratos kratos 527 0/0 kratos-info kratos_info provider |
| 74 | +oauth-offer hydra hydra 362 0/0 oauth oauth provider |
| 75 | +
|
| 76 | +Integration provider Requirer Interface Type Message |
| 77 | +hydra:hydra hydra:hydra hydra_peers peer |
| 78 | +hydra:hydra-endpoint-info kratos:hydra-endpoint-info hydra_endpoints regular |
| 79 | +hydra:hydra-endpoint-info login-ui:hydra-endpoint-info hydra_endpoints regular |
| 80 | +ingress:ingress hydra:public-ingress ingress regular |
| 81 | +ingress:ingress kratos:public-ingress ingress regular |
| 82 | +ingress:ingress login-ui:ingress ingress regular |
| 83 | +kratos:kratos-info login-ui:kratos-info kratos_info regular |
| 84 | +kratos:kratos-peers kratos:kratos-peers kratos-peers peer |
| 85 | +login-ui:identity-platform-login-ui login-ui:identity-platform-login-ui identity_platform_login_ui_peers peer |
| 86 | +login-ui:ui-endpoint-info hydra:ui-endpoint-info login_ui_endpoints regular |
| 87 | +login-ui:ui-endpoint-info kratos:ui-endpoint-info login_ui_endpoints regular |
| 88 | +postgresql:database hydra:pg-database postgresql_client regular |
| 89 | +postgresql:database kratos:pg-database postgresql_client regular |
| 90 | +``` |
| 91 | +```` |
| 92 | + |
| 93 | +````{dropdown} juju status --relations --model core |
| 94 | +``` |
| 95 | +Model Controller Cloud/Region Version SLA Timestamp |
| 96 | +core local-microk8s local-microk8s/localhost 3.6.8 unsupported 16:51:56-04:00 |
| 97 | +
|
| 98 | +App Version Status Scale Charm Channel Rev Address Exposed Message |
| 99 | +postgresql-k8s 14.15 active 1 postgresql-k8s 14/stable 495 10.152.183.109 no |
| 100 | +self-signed-certificates active 1 self-signed-certificates 1/stable 317 10.152.183.149 no |
| 101 | +traefik-public 2.11.0 active 1 traefik-k8s latest/edge 242 10.152.183.234 no Serving at 10.64.140.44 |
| 102 | +
|
| 103 | +Unit Workload Agent Address Ports Message |
| 104 | +postgresql-k8s/0* active idle 10.1.253.243 Primary |
| 105 | +self-signed-certificates/0* active idle 10.1.253.237 |
| 106 | +traefik-public/0* active idle 10.1.253.244 Serving at 10.64.140.44 |
| 107 | +
|
| 108 | +Offer Application Charm Rev Connected Endpoint Interface Role |
| 109 | +ingress traefik-public traefik-k8s 236 3/3 ingress ingress provider |
| 110 | +postgresql postgresql-k8s postgresql-k8s 495 2/2 database postgresql_client provider |
| 111 | +send-ca-cert self-signed-certificates self-signed-certificates 317 0/0 send-ca-cert certificate_transfer provider |
| 112 | +traefik-route traefik-public traefik-k8s 236 0/0 traefik-route traefik_route provider |
| 113 | +
|
| 114 | +Integration provider Requirer Interface Type Message |
| 115 | +postgresql-k8s:database-peers postgresql-k8s:database-peers postgresql_peers peer |
| 116 | +postgresql-k8s:restart postgresql-k8s:restart rolling_op peer |
| 117 | +postgresql-k8s:upgrade postgresql-k8s:upgrade upgrade peer |
| 118 | +self-signed-certificates:certificates traefik-public:certificates tls-certificates regular |
| 119 | +traefik-public:peers traefik-public:peers traefik_peers peer |
| 120 | +``` |
| 121 | +```` |
| 122 | + |
| 123 | +````{dropdown} juju status --relations --model istio-system |
| 124 | +``` |
| 125 | +Model Controller Cloud/Region Version SLA Timestamp |
| 126 | +istio-system local-microk8s local-microk8s/localhost 3.6.8 unsupported 16:52:40-04:00 |
| 127 | +
|
| 128 | +App Version Status Scale Charm Channel Rev Address Exposed Message |
| 129 | +istio-ingress-k8s active 1 istio-ingress-k8s 2/edge 43 10.152.183.28 no Serving at 10.64.140.43 |
| 130 | +istio-k8s active 1 istio-k8s 2/edge 38 10.152.183.75 no |
| 131 | +
|
| 132 | +Unit Workload Agent Address Ports Message |
| 133 | +istio-ingress-k8s/0* active idle 10.1.253.202 Serving at 10.64.140.43 |
| 134 | +istio-k8s/0* active idle 10.1.253.201 |
| 135 | +
|
| 136 | +Offer Application Charm Rev Connected Endpoint Interface Role |
| 137 | +istio-ingress-k8s istio-ingress-k8s istio-ingress-k8s 43 1/1 ingress ingress provider |
| 138 | + ingress-unauthenticated ingress provider |
| 139 | +
|
| 140 | +Integration provider Requirer Interface Type Message |
| 141 | +istio-ingress-k8s:peers istio-ingress-k8s:peers istio_ingress_k8s_peers peer |
| 142 | +istio-k8s:peers istio-k8s:peers istio_k8s_peers peer |
| 143 | +``` |
| 144 | +```` |
| 145 | + |
| 146 | +````{dropdown} juju status --relations --model bookinfo |
| 147 | +``` |
| 148 | +Model Controller Cloud/Region Version SLA Timestamp |
| 149 | +bookinfo local-microk8s local-microk8s/localhost 3.6.8 unsupported 16:53:08-04:00 |
| 150 | +
|
| 151 | +SAAS Status Store URL |
| 152 | +istio-ingress-k8s active local-microk8s admin/istio-system.istio-ingress-k8s |
| 153 | +
|
| 154 | +App Version Status Scale Charm Channel Rev Address Exposed Message |
| 155 | +bookinfo-details-k8s active 1 bookinfo-details-k8s latest/stable 1 10.152.183.173 no Ready |
| 156 | +bookinfo-productpage-k8s active 1 bookinfo-productpage-k8s latest/stable 1 10.152.183.141 no Ready with 2 backend services |
| 157 | +bookinfo-reviews-k8s active 1 bookinfo-reviews-k8s latest/stable 1 10.152.183.145 no Running version v1 |
| 158 | +istio-beacon-k8s active 1 istio-beacon-k8s 2/edge 38 10.152.183.105 no |
| 159 | +
|
| 160 | +Unit Workload Agent Address Ports Message |
| 161 | +bookinfo-details-k8s/0* active idle 10.1.253.247 Ready |
| 162 | +bookinfo-productpage-k8s/0* active idle 10.1.253.248 Ready with 2 backend services |
| 163 | +bookinfo-reviews-k8s/0* active idle 10.1.253.250 Running version v1 |
| 164 | +istio-beacon-k8s/0* active idle 10.1.253.246 |
| 165 | +
|
| 166 | +Integration provider Requirer Interface Type Message |
| 167 | +bookinfo-details-k8s:details bookinfo-productpage-k8s:details bookinfo-details regular |
| 168 | +bookinfo-reviews-k8s:reviews bookinfo-productpage-k8s:reviews bookinfo-reviews regular |
| 169 | +istio-beacon-k8s:peers istio-beacon-k8s:peers istio_beacon_k8s_peers peer |
| 170 | +istio-beacon-k8s:service-mesh bookinfo-details-k8s:service-mesh service_mesh regular |
| 171 | +istio-beacon-k8s:service-mesh bookinfo-productpage-k8s:service-mesh service_mesh regular |
| 172 | +istio-beacon-k8s:service-mesh bookinfo-reviews-k8s:service-mesh service_mesh regular |
| 173 | +istio-ingress-k8s:ingress bookinfo-productpage-k8s:ingress ingress regular |
| 174 | +``` |
| 175 | +```` |
| 176 | + |
| 177 | +From this stage, we can: |
| 178 | +* browse to the Bookinfo application. The URL is of the format `https://ISTIO_INGRESS_IP/bookinfo-bookinfo-productpage-k8s/productpage?u=normal` - use `juju run --model bookinfo bookinfo-productpage-k8s/leader get-url` to obtain the real URL. |
| 179 | +* log into the Identity login page (login ui). The URL is of the format `https://TRAEFIK_IP/iam-login-ui/ui/login` - use `juju run --model core traefik-public/leader show-proxied-endpoints` to obtain the real URL. |
| 180 | + |
| 181 | +But browsing to the Bookinfo application did not require any authentication. Next, we configure the Istio ingress to enforce authentication using the Identity Platform. |
| 182 | + |
| 183 | +```{note} |
| 184 | +Throughout this tutorial you will log into the identity platform a few times. While it works in any browser configuration, using incognito sessions is recommended because its easy to close the session to reset any login cookies. Its recommended that every time you try to log in fresh, you close your incognito session and start a new one. |
| 185 | +``` |
| 186 | + |
| 187 | +## Configure the Identity Platform to use the Istio Ingress |
| 188 | + |
| 189 | +### Configure the Istio Ingress to use TLS |
| 190 | + |
| 191 | +The Identity Platform by default requires everything to be ingressed using https, but the [Get started with Charmed Istio](../tutorial/get-started-with-the-charmed-istio-mesh.md) tutorial used http. To enable https, we can obtain certificates from the `self-signed-certificates` provided deployed in the Identity Platform tutorial by offering the certificate provider: |
| 192 | + |
| 193 | +```bash |
| 194 | +juju offer core.self-signed-certificates:certificates certificates |
| 195 | +``` |
| 196 | + |
| 197 | +and using it in istio-ingress-k8s: |
| 198 | + |
| 199 | +```bash |
| 200 | +juju consume --model istio-system core.certificates |
| 201 | +juju relate --model istio-system istio-ingress-k8s:certificates certificates |
| 202 | +``` |
| 203 | + |
| 204 | +### Ingress the Identity Platform through Istio |
| 205 | + |
| 206 | +Out of the box, the [Identity Platform tutorial](https://charmhub.io/topics/canonical-identity-platform/tutorials/e2e-tutorial) uses [Traefik](https://github.com/canonical/traefik-k8s-operator) as an ingress. To reconfigure that deployment to use our istio-ingress-k8s, consume the istio-ingress-k8s in the iam model: |
| 207 | + |
| 208 | +```bash |
| 209 | +juju consume --model iam istio-system.istio-ingress-k8s |
| 210 | +``` |
| 211 | + |
| 212 | +Then change the ingress for all the Identity charms from Traefik to istio-ingress-k8s: |
| 213 | + |
| 214 | +```bash |
| 215 | +juju remove-relation --model iam hydra:public-ingress ingress |
| 216 | +juju relate --model iam hydra:public-ingress istio-ingress-k8s:ingress-unauthenticated |
| 217 | +juju remove-relation --model iam kratos:public-ingress ingress |
| 218 | +juju relate --model iam kratos:public-ingress istio-ingress-k8s:ingress-unauthenticated |
| 219 | +juju remove-relation --model iam login-ui:ingress ingress |
| 220 | +juju relate --model iam login-ui:ingress istio-ingress-k8s:ingress-unauthenticated |
| 221 | +``` |
| 222 | + |
| 223 | +Once this settles, we should be able to complete the login flow through the new ingress at `https://ISTIO_INGRESS_IP/iam-login-ui/ui/login`. |
| 224 | + |
| 225 | +## Add Authentication to the Istio Ingress using the Identity Platform |
| 226 | + |
| 227 | +By default, traffic is allowed through the Istio Ingress unauthenticated. To add an authentication flow to that traffic, we connect the istio-ingress-k8s to istio-k8s to send additional configurations: |
| 228 | + |
| 229 | +```bash |
| 230 | +juju relate --model istio-system istio-ingress-k8s:istio-ingress-config istio-k8s:istio-ingress-config |
| 231 | +``` |
| 232 | + |
| 233 | +deploy `oauth2-proxy`: |
| 234 | + |
| 235 | +```bash |
| 236 | +# Deploy oauth2-proxy and provide it with certificates used by other applications |
| 237 | +juju deploy --model istio-system oauth2-proxy-k8s oauth2-proxy --channel=edge --trust |
| 238 | +juju consume --model istio-system core.send-ca-cert |
| 239 | +juju relate --model istio-system oauth2-proxy:receive-ca-cert send-ca-cert |
| 240 | +juju relate --model istio-system oauth2-proxy:ingress istio-ingress-k8s:ingress-unauthenticated |
| 241 | +``` |
| 242 | + |
| 243 | +and connect `oauth2-proxy` to the identity platform and istio-ingress: |
| 244 | + |
| 245 | +```bash |
| 246 | +juju consume --model istio-system iam.oauth-offer |
| 247 | +juju relate --model istio-system oauth2-proxy:oauth oauth-offer |
| 248 | + |
| 249 | +juju relate --model istio-system oauth2-proxy:forward-auth istio-ingress-k8s:forward-auth |
| 250 | +``` |
| 251 | + |
| 252 | +Now when we browse to the Bookinfo application at `https://ISTIO_INGRESS_IP/bookinfo-bookinfo-productpage-k8s/productpage?u=normal`, we will be prompted first to log in through the Identity Platform. |
| 253 | + |
| 254 | +## How to ingress some applications without authentication |
| 255 | + |
| 256 | +istio-ingress-k8s offers two `ingress` integration endpoints, `ingress` and `ingress-unauthenticated`. These both support the same interface, but differ in how they handle authentication: |
| 257 | +* `ingress`: traffic ingressed using this integration **will always be authenticated *if authentication is configured on this istio-ingress-k8s***, otherwise traffic will be unauthenticated |
| 258 | +* `ingress-unauthenticated`: traffic ingressed using this integration **will never be authenticated** |
| 259 | + |
| 260 | +Typically, `ingress` is the integration you need. But when some applications need to selectively be offered without authentication, use `ingress-unauthenticated` to keep them unrestricted. |
| 261 | + |
| 262 | +To try this out, deploy the [catalogue-k8s](https://github.com/canonical/catalogue-k8s-operator/) charm and ingress it without authentication: |
| 263 | + |
| 264 | +```bash |
| 265 | +juju deploy --model bookinfo catalogue-k8s catalogue |
| 266 | +juju relate --model catalogue istio-ingress-k8s:ingress-unauthenticated |
| 267 | +``` |
| 268 | + |
| 269 | +Now (in a new browser session, just so you know you're not already logged in) browse to Catalogue at `https://ISTIO_INGRESS_IP/bookinfo-catalogue`. The application will be accessible without a login. |
| 270 | + |
| 271 | +## Wrapping up |
| 272 | + |
| 273 | +Congratulations! You've successfully: |
| 274 | + |
| 275 | +- configured istio-ingress-k8s to use the Identity Platform for authentication |
| 276 | +- logged into the Identity Platform to access an application |
| 277 | +- deployed an application that is never authenticated |
| 278 | + |
| 279 | +## Teardown |
| 280 | + |
| 281 | +To clean up the resources created in this tutorial, run: |
| 282 | + |
| 283 | +```bash |
| 284 | +juju destroy-model iam |
| 285 | +juju destroy-model core |
| 286 | +juju destroy-model istio-system |
| 287 | +juju destroy-model bookinfo |
| 288 | +``` |
0 commit comments