I have a two microservices(powered by spring boot) running. Each of which is secured with oauth2. And I am using keycloak as the provider. Both these services use different flows.
Service1 uses Direct Grant Access flow(Resource owner password grant) and Service2 uses Standard flow(Authorization Code grant).
So when the user calls an endpoint on Service1, it should have the bearer token with it and when the user calls Service2, user will be redirected to the keycloak login page.
I want to separate this logic from both the microservices and put it in spring cloud gateway.
I have the routing part setup but I am not able to figure out how to configure the security part.
I have something like this
spring:
security:
oauth2:
client:
provider:
keycloak:
token-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/token
authorization-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/auth
userinfo-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/userinfo
user-name-attribute: preferred_username
registration:
keycloak-with-password-flow:
provider: keycloak
client-id: Service1
client-secret: 2cff54cf-f29e-4f0a-905d-33dd12186dc2
authorization-grant-type: password
redirect-uri: "{baseUrl}/login/oauth2/code/keycloak"
keycloak-without-authcode-scope:
provider: keycloak
client-id: Service2
client-secret: 2c13020a-3e3f-40f3-837f-165f8a0c027a
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/keycloak"
With this setting, when I call an endpoint on Service1 with the bearer token, I am being redirected to login page.
Could someone let me know how to achieve this?
Related
We use envoy 1.24 docker image and have envoy yaml configured to go to service A successfully. After that we decided to go with envoy external auth
We did configuration as per instructions and got it to work locally. There is a auth service that is run as docker image and we have envoy running in docker, pointing to auth docker image address.
Problem occurred when we shipped these two services to Google Cloud Run. While we didn't had any auth configured, we successfully managed to trigger GRPC requests on service A. Moment we added external auth, and tried to push everything to GCP Cloud Run, we bumped into issue:
upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: immediate connect error: Cannot assign requested address'
Envoy config looks like this:
Filter:
- name: envoy.filters.http.ext_authz
typed_config:
"#type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
grpc_service:
envoy_grpc:
cluster_name: auth
transport_api_version: V3
Cluster:
- name: auth
type: STRICT_DNS
lb_policy: ROUND_ROBIN
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"#type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: { }
load_assignment:
cluster_name: auth
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: cloud-run-address
port_value: 443
If I try to hit the auth service directly via GRPC check request I am able to do so without any issues. Even if I set url of auth service to service A, it is resolving successfully and giving me error accordingly.
Since we use GRPC for communication, all services are http2 enabled.
What are we doing wrong? We need to be able to authorise using external auth service hosted on cloud run. Any help to get this to work out is appreciated. Thx
Managed to get it working. Had to do couple of changes to cluster config:
- name: auth
type: STRICT_DNS
lb_policy: ROUND_ROBIN
dns_lookup_family: V4_ONLY
http2_protocol_options: {}
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"#type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
load_assignment:
cluster_name: auth
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: internal_ip_address_from_lb
port_value: 443
Furhter more, in address field I have added IP address from load balancer that I have created. Type of load balancer is internal load balancer, configured to go directly to my cloud run auth service.
I need to solve the problem of redirection in docker-compose using either static IP addresses visible from the host or another method. I am trying to deploy 2 solutions, namely grafana and keycloak. Unfortunately, if I use standard port mapping to localhost in the redirection process keycloak tries to redirect to grafana container, which cannot be accessed by the host as DNS won't solve the name. Is there a way to assign said addresses to the container in a way that would solve this problem or allow containers to be accessed from localhost altogether. (I have tires network_mode: host) but this approach doesn't work on Windows 10 and has many other problems.
Exemplary docker file:
version: "3.9"
services:
keycloak:
build: ./keycloak/
container_name: keycloak
ports:
- "8180:8180"
grafana:
image: bitnami/grafana:latest
container_name: grafana
ports:
- 3000:3000
volumes:
- ./grafana/grafana.ini:/opt/bitnami/grafana/conf/grafana.ini
Here is my grafana config:
[server]
# Protocol (http, https, h2, socket)
;protocol = http
http_port = 3000
# The public facing domain name used to access grafana from a browser
;domain = localhost
# Redirect to correct domain if host header does not match domain
# Prevents DNS rebinding attacks
;enforce_domain = false
# The full public facing url you use in browser, used for redirects and emails
# If you use reverse proxy and sub path specify full url (with sub path)
;root_url = %(protocol)s://%(domain)s:%(http_port)s/
root_url = http://host.docker.internal:3000/
[auth]
# Login cookie name
login_cookie_name = grafana_session
#################################### Generic OAuth ##########################
[auth.generic_oauth]
enabled = true
name = Keycloack
allow_sign_up = true
client_id = grafana
scopes = openid email profile
auth_url = http://host.docker.internal:8080/auth/realms/master/protocol/openid-connect/auth
token_url = http://host.docker.internal:8080/auth/realms/master/protocol/openid-connect/token
api_url = http://host.docker.internal:8080/auth/realms/master/protocol/openid-connect/userinfo
client_secret = secret
role_attribute_path = contains(info.groups[*], 'admin') && 'Admin' || contains(info.groups[*], 'editor') && 'Editor' || 'Viewer'
The rest is default.
I have tried all variations of localhost keycloak and grafana possible, with no results whatsoever.
In a microservices architecture, I have three containers, front(angular), gateway(spring cloud gateway) and security provider(keycloak) among others
For security configurations in the gateway
If I set
spring:
security:
oauth2:
client:
provider:
keycloak:
issuer-uri: http://keycloak-container:8080
I can start gateway container and reach the security container
But
spring:
security:
oauth2:
client:
provider:
keycloak:
issuer-uri: https://public-dns-of-keycloak-container.mydomain.com
Throws me this error
... 61 common frames omitted
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://public-dns-of-keycloak-container.mydomain.com/auth/realms/boromoi_app/.well-known/openid-configuration":
Connection timed out (Connection timed out); nested exception is java.net.ConnectException: Connection timed out (Connection timed out)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:751) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:654) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.security.oauth2.jwt.JwtDecoderProviderConfigurationUtils.getConfiguration(JwtDecoderProviderConfigurationUtils.java:71)
~[spring-security-oauth2-jose-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
... 69 common frames omitted
Caused by: java.net.ConnectException: Connection timed out (Connection timed out)
https://public-dns-of-keycloak-container.mydomain.com is the URL used by front to reach security container
Authentication scenario with keycloak security proxy
I have built the architecture shown in the image.
A client authentication request reaches the keycloak security proxy docker container.
Proxy asks the actual keycloak server docker container
Keycloak Server asks an external LDAP for user credentials.
Keycloak server replies OK.
Keycloak proxy replies OK and passes control to the external application URL.
The problem is that after successful authentication, the URL of the host server (i.e. where the keycloak proxy container and keycloak authentication container lie) appears on the address bar of the browser instead of the actual external application URL.
For example, if the host machine where the keycloak containers lie is keycloak.containers.gr, and the external application domain name is www.external.application.gr, then, after a successful login to the keycloak SSO login page, the URL in the address bar appears to be http://keycloak.containers.gr instead of http://www.external.application.gr.
This fact destroys all the relative css, js scripts, etc. attached to the site
www.external.application.gr.
KEYCLOAK SECURITY PROXY CONFIGURATION
I use a proxy.json for the keycloak security proxy configuration
{
"target-url": "http://www.external.application.gr",
"bind-address": "0.0.0.0",
"send-access-token": true,
"http-port": "8180",
"https-port": "8443",
"applications": [
{
"base-path": "/",
"adapter-config": {
"realm": "internal_applications",
"auth-server-url": "http://keycloak.containers.gr:8202/auth",
"resource": "test_app",
"ssl-required": "external",
"credentials": {
"secret": "xxxxx-xxx-xxx-xxxx-xxxxxxxxxxx"
}
},
"constraints": [
{
"pattern": "/*",
"authenticate": true
}
],
"proxy-address-forwarding": true
}
]
}
NOTE:
I have tried to change the "bind-address": "0.0.0.0" parameter, from 0.0.0.0 to the IP of the www.external.application.gr, but with no luck...
I have a Spring Cloud Eureka client instance running inside docker, and I would like the client to register itself the host's IP address rather than the container's hostname to the Eureka server, so I set eureka.instance.ip-address: xx.xx.xx.xx and eureka.instance.prefer-ip-address: true to the client's application.yml, but that does not work, it still registers the container's hostname to the server, any help is appreciated!
spring:
application:
name: uaa-service
server:
port: 8799
eureka:
service-url:
defaultZone: https://XX.YY.ZZ/eureka/
instance:
prefer-ip-address: true
ip-address: xx.xx.xx.xx
My Spring Boot version is 2.0.0.RELEASE and Spring Cloud being Finchley.M9.
I'm using the same version of spring-boot and have a similar problem
But I think you are confusing IP address with the instance ID.
See this link: https://github.com/spring-cloud/spring-cloud-netflix/issues/1646#issuecomment-275121055
When you hover the mouse over the link or click on it, does it show the right IP-Address?
Anyway, I have two applications, one using spring-boot 1.5 where this property works.
With the 2.0 version the application always use the machine IP, instead what I informed in the eureka.instance.ip-address.
Edit > I reported a bug here: https://github.com/spring-cloud/spring-cloud-netflix/issues/2878
Give this in your spring service
spring:
application:
name: uaa-service
cloud:
inetutils:
ignored-interfaces:
- eth0
- eth1
- eth2
- eth3
- lo
Taken from this