github.com/argoproj/argo-cd/v3@v3.2.1/docs/developer-guide/extensions/proxy-extensions.md (about) 1 # Proxy Extensions 2 3 !!! warning "Beta Feature (Since 2.7.0)" 4 5 This feature is in the [Beta](https://github.com/argoproj/argoproj/blob/main/community/feature-status.md#beta) stage. 6 It is generally considered stable, but there may be unhandled edge cases. 7 8 ## Overview 9 10 With UI extensions it is possible to enhance Argo CD web interface to 11 provide valuable data to the user. However the data is restricted to 12 the resources that belongs to the Application. With proxy extensions 13 it is also possible to add additional functionality that have access 14 to data provided by backend services. In this case Argo CD API server 15 acts as a reverse-proxy authenticating and authorizing incoming 16 requests before forwarding to the backend service. 17 18 ## Configuration 19 20 As proxy extension is in [Alpha][1] phase, the feature is disabled by 21 default. To enable it, it is necessary to configure the feature flag 22 in Argo CD command parameters. The easiest way to properly enable 23 this feature flag is by adding the `server.enable.proxy.extension` key 24 in the existing `argocd-cmd-params-cm`. For example: 25 26 ```yaml 27 apiVersion: v1 28 kind: ConfigMap 29 metadata: 30 name: argocd-cmd-params-cm 31 namespace: argocd 32 data: 33 server.enable.proxy.extension: 'true' 34 ``` 35 36 Once the proxy extension is enabled, it can be configured in the main 37 Argo CD configmap ([argocd-cm][2]). 38 39 The example below demonstrates all possible configurations available 40 for proxy extensions: 41 42 ```yaml 43 apiVersion: v1 44 kind: ConfigMap 45 metadata: 46 name: argocd-cm 47 namespace: argocd 48 data: 49 extension.config: | 50 extensions: 51 - name: httpbin 52 backend: 53 connectionTimeout: 2s 54 keepAlive: 15s 55 idleConnectionTimeout: 60s 56 maxIdleConnections: 30 57 services: 58 - url: http://httpbin.org 59 headers: 60 - name: some-header 61 value: '$some.argocd.secret.key' 62 cluster: 63 name: some-cluster 64 server: https://some-cluster 65 ``` 66 67 Proxy extensions can also be provided individually using dedicated 68 Argo CD configmap keys for better GitOps operations. The example below 69 demonstrates how to configure the same hypothetical httpbin config 70 above using a dedicated key: 71 72 ```yaml 73 apiVersion: v1 74 kind: ConfigMap 75 metadata: 76 name: argocd-cm 77 namespace: argocd 78 data: 79 extension.config.httpbin: | 80 connectionTimeout: 2s 81 keepAlive: 15s 82 idleConnectionTimeout: 60s 83 maxIdleConnections: 30 84 services: 85 - url: http://httpbin.org 86 headers: 87 - name: some-header 88 value: '$some.argocd.secret.key' 89 cluster: 90 name: some-cluster 91 server: https://some-cluster 92 ``` 93 94 Attention: Extension names must be unique in the Argo CD configmap. If 95 duplicated keys are found, the Argo CD API server will log an error 96 message and no proxy extension will be registered. 97 98 Note: There is no need to restart Argo CD Server after modifying the 99 `extension.config` entry in Argo CD configmap. Changes will be 100 automatically applied. A new proxy registry will be built making 101 all new incoming extensions requests (`<argocd-host>/extensions/*`) to 102 respect the new configuration. 103 104 Every configuration entry is explained below: 105 106 #### `extensions` (_list_) 107 108 Defines configurations for all extensions enabled. 109 110 #### `extensions.name` (_string_) 111 112 (mandatory) 113 114 Defines the endpoint that will be used to register the extension 115 route. For example, if the value of the property is `extensions.name: 116 my-extension` then the backend service will be exposed under the 117 following url: 118 119 <argocd-host>/extensions/my-extension 120 121 #### `extensions.backend.connectionTimeout` (_duration string_) 122 123 (optional. Default: 2s) 124 125 Is the maximum amount of time a dial to the extension server will wait 126 for a connect to complete. 127 128 #### `extensions.backend.keepAlive` (_duration string_) 129 130 (optional. Default: 15s) 131 132 Specifies the interval between keep-alive probes for an active network 133 connection between the API server and the extension server. 134 135 #### `extensions.backend.idleConnectionTimeout` (_duration string_) 136 137 (optional. Default: 60s) 138 139 Is the maximum amount of time an idle (keep-alive) connection between 140 the API server and the extension server will remain idle before 141 closing itself. 142 143 #### `extensions.backend.maxIdleConnections` (_int_) 144 145 (optional. Default: 30) 146 147 Controls the maximum number of idle (keep-alive) connections between 148 the API server and the extension server. 149 150 #### `extensions.backend.services` (_list_) 151 152 Defines a list with backend url by cluster. 153 154 #### `extensions.backend.services.url` (_string_) 155 156 (mandatory) 157 158 Is the address where the extension backend must be available. 159 160 #### `extensions.backend.services.headers` (_list_) 161 162 If provided, the headers list will be added on all outgoing requests 163 for this service config. Existing headers in the incoming request with 164 the same name will be overridden by the one in this list. Reserved header 165 names will be ignored (see the [headers](#incoming-request-headers) below). 166 167 #### `extensions.backend.services.headers.name` (_string_) 168 169 (mandatory) 170 171 Defines the name of the header. It is a mandatory field if a header is 172 provided. 173 174 #### `extensions.backend.services.headers.value` (_string_) 175 176 (mandatory) 177 178 Defines the value of the header. It is a mandatory field if a header is 179 provided. The value can be provided as verbatim or as a reference to an 180 Argo CD secret key. In order to provide it as a reference, it is 181 necessary to prefix it with a dollar sign. 182 183 Example: 184 185 value: '$some.argocd.secret.key' 186 187 In the example above, the value will be replaced with the one from 188 the argocd-secret with key 'some.argocd.secret.key'. 189 190 #### `extensions.backend.services.cluster` (_object_) 191 192 (optional) 193 194 If provided, and multiple services are configured, will have to match 195 the application destination name or server to have requests properly 196 forwarded to this service URL. If there are multiple backends for the 197 same extension this field is required. In this case, it is necessary 198 to provide both values to avoid problems with applications unable to 199 send requests to the proper backend service. If only one backend 200 service is configured, this field is ignored, and all requests are 201 forwarded to the configured one. 202 203 #### `extensions.backend.services.cluster.name` (_string_) 204 205 (optional) 206 207 It will be matched with the value from 208 `Application.Spec.Destination.Name` 209 210 #### `extensions.backend.services.cluster.server` (_string_) 211 212 (optional) 213 214 It will be matched with the value from 215 `Application.Spec.Destination.Server`. 216 217 ## Usage 218 219 Once a proxy extension is configured it will be made available under 220 the `/extensions/<extension-name>` endpoint exposed by Argo CD API 221 server. The example above will proxy requests to 222 `<apiserver-host>/extensions/httpbin/` to `http://httpbin.org`. 223 224 The diagram below illustrates an interaction possible with this 225 configuration: 226 227 ``` 228 ┌─────────────┐ 229 │ Argo CD UI │ 230 └────┬────────┘ 231 │ ▲ 232 GET <apiserver-host>/extensions/httpbin/anything │ │ 200 OK 233 + authn/authz headers │ │ 234 ▼ │ 235 ┌─────────┴────────┐ 236 │Argo CD API Server│ 237 └──────┬───────────┘ 238 │ ▲ 239 GET http://httpbin.org/anything │ │ 200 OK 240 │ │ 241 ▼ │ 242 ┌────────┴────────┐ 243 │ Backend Service │ 244 └─────────────────┘ 245 ``` 246 247 ### Incoming Request Headers 248 249 Note that Argo CD API Server requires additional HTTP headers to be 250 sent in order to enforce if the incoming request is authenticated and 251 authorized before being proxied to the backend service. The headers 252 are documented below: 253 254 #### `Cookie` 255 256 Argo CD UI keeps the authentication token stored in a cookie 257 (`argocd.token`). This value needs to be sent in the `Cookie` header 258 so the API server can validate its authenticity. 259 260 Example: 261 262 Cookie: argocd.token=eyJhbGciOiJIUzI1Ni... 263 264 The entire Argo CD cookie list can also be sent. The API server will 265 only use the `argocd.token` attribute in this case. 266 267 #### `Argocd-Application-Name` (mandatory) 268 269 This is the name of the project for the application for which the 270 extension is being invoked. The header value must follow the format: 271 `"<namespace>:<app-name>"`. 272 273 Example: 274 275 Argocd-Application-Name: namespace:app-name 276 277 #### `Argocd-Project-Name` (mandatory) 278 279 The logged in user must have access to this project in order to be 280 authorized. 281 282 Example: 283 284 Argocd-Project-Name: default 285 286 Argo CD API Server will ensure that the logged in user has the 287 permission to access the resources provided by the headers above. The 288 validation is based on pre-configured [Argo CD RBAC rules][3]. The 289 same headers are also sent to the backend service. The backend service 290 must also validate if the validated headers are compatible with the 291 rest of the incoming request. 292 293 ### Outgoing Requests Headers 294 295 Requests sent to backend services will be decorated with additional 296 headers. The outgoing request headers are documented below: 297 298 #### `Argocd-Target-Cluster-Name` 299 300 Will be populated with the value from `app.Spec.Destination.Name` if 301 it is not empty string in the application resource. 302 303 #### `Argocd-Target-Cluster-URL` 304 305 Will be populated with the value from `app.Spec.Destination.Server` if 306 it is not empty string is the Application resource. 307 308 Note that additional pre-configured headers can be added to outgoing 309 request. See [backend service headers](#extensionsbackendservicesheaders-list) 310 section for more details. 311 312 #### `Argocd-Username` 313 314 Will be populated with the username logged in Argo CD. This is primarily useful for display purposes. 315 To identify a user for programmatic needs, `Argocd-User-Id` is probably a better choice. 316 317 #### `Argocd-User-Id` 318 319 Will be populated with the internal user id, most often defined by the `sub` claim, logged in Argo CD. 320 321 #### `Argocd-User-Groups` 322 323 Will be populated with the configured RBAC scopes, most often the `groups` claim, from the user logged in Argo CD. 324 325 ### Multi Backend Use-Case 326 327 In some cases when Argo CD is configured to sync with multiple remote 328 clusters, there might be a need to call a specific backend service in 329 each of those clusters. The proxy-extension can be configured to 330 address this use-case by defining multiple services for the same 331 extension. Consider the following configuration as an example: 332 333 ```yaml 334 extension.config: | 335 extensions: 336 - name: some-extension 337 backend: 338 services: 339 - url: http://extension-name.com:8080 340 cluster 341 name: kubernetes.local 342 - url: https://extension-name.ppd.cluster.k8s.local:8080 343 cluster 344 server: user@ppd.cluster.k8s.local 345 ``` 346 347 In the example above, the API server will inspect the Application 348 destination to verify which URL should be used to proxy the incoming 349 request to. 350 351 ## Security 352 353 When a request to `/extensions/*` reaches the API Server, it will 354 first verify if it is authenticated with a valid token. It does so by 355 inspecting if the `Cookie` header is properly sent from Argo CD UI 356 extension. 357 358 Once the request is authenticated it is then verified if the 359 user has permission to invoke this extension. The permission is 360 enforced by Argo CD RBAC configuration. The details about how to 361 configure the RBAC for proxy-extensions can be found in the [RBAC 362 documentation][3] page. 363 364 Once the request is authenticated and authorized by the API server, it 365 is then sanitized before being sent to the backend service. The 366 request sanitization will remove sensitive information from the 367 request like the `Cookie` and `Authorization` headers. 368 369 A new `Authorization` header can be added to the outgoing request by 370 defining it as a header in the `extensions.backend.services.headers` 371 configuration. Consider the following example: 372 373 ```yaml 374 extension.config: | 375 extensions: 376 - name: some-extension 377 backend: 378 services: 379 - url: http://extension-name.com:8080 380 headers: 381 - name: Authorization 382 value: '$some-extension.authorization.header' 383 ``` 384 385 In the example above, all requests sent to 386 `http://extension-name.com:8080` will have an additional 387 `Authorization` header. The value of this header will be the one from 388 the [argocd-secret](../../operator-manual/argocd-secret-yaml.md) with 389 key `some-extension.authorization.header` 390 391 [1]: https://github.com/argoproj/argoproj/blob/master/community/feature-status.md 392 [2]: https://argo-cd.readthedocs.io/en/stable/operator-manual/argocd-cm.yaml 393 [3]: ../../operator-manual/rbac.md#the-extensions-resource