IdentityServer 4 in k8s behind loadbalancer - kubernetes

I've a identityserver deployed to kubernetes. I also konfigured google and facebook auth (see below). The HTTPS Termination is done but the K8s Ingress.
To get the identity still working with https i set forwarding rules (see below).
But from now on i get the following error and a HTTP 500 When a User tries to login. Terror occurs when the
System.InvalidOperationException: No authentication handler is
configured to handle the scheme: Identity.External
The line of code that triggers the error is in the account controller:
signInManager.ExternalLoginSignInAsync(provider, userIdClaim.Value, true);
My identity server startup looks like this:
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedProto,
ForwardLimit = null,
RequireHeaderSymmetry = false
});
app.UseIdentityServer();
app.UseGoogleAuthentication(new GoogleOptions
{
AuthenticationScheme = "Google",
DisplayName = "Google",
SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,
ClientId = "dfdfsf",
ClientSecret = "-cf-"
});
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
what am I missing?

Related

enabling oauth2 with pgadmin and gitlab

I've deployed pgadmin on Kubernetes and I'm trying to enable oauth2 as per the pgadmin docs
This is the oauth config which I've passed in:
AUTHENTICATION_SOURCES = ['oauth2', 'internal']
OAUTH2_CONFIG = [
{
# The name of the of the oauth provider, ex: github, google
'OAUTH2_NAME': 'gitlab',
# The display name, ex: Google
'OAUTH2_DISPLAY_NAME': 'Gitlab',
# Oauth client id
'OAUTH2_CLIENT_ID': 'my-client-id-here',
# Oauth secret
'OAUTH2_CLIENT_SECRET': 'my-client-secret-here',
# URL to generate a token,
# Ex: https://github.com/login/oauth/access_token
'OAUTH2_TOKEN_URL': 'https://gitlab.com/oauth/token',
# URL is used for authentication,
# Ex: https://github.com/login/oauth/authorize
'OAUTH2_AUTHORIZATION_URL': "https://gitlab.com/oauth/authorize",
# Oauth base url, ex: https://api.github.com/
'OAUTH2_API_BASE_URL': 'https://gitlab.com/api/v4/',
# Name of the Endpoint, ex: user
'OAUTH2_USERINFO_ENDPOINT': 'user',
# Font-awesome icon, ex: fa-github
'OAUTH2_ICON': 'fa-gitlab',
# UI button colour, ex: #0000ff
'OAUTH2_BUTTON_COLOR': '#E24329',
}
]
OAUTH2_AUTO_CREATE_USER = True
I've added the application on Gitlab. The redirect URIs are:
https://pgadmin.nonprod.example.io/oauth2/authorize
http://pgadmin.nonprod.example.io/oauth2/authorize
I've give the application the following scopes:
api
openid
profile
email
I'm testing it locally with the pgadmin ingress and my local minikube cluster. I keep getting the following error when I click the 'Sign in with Gitlab' button:
{
success: 0,
errormsg: "403 Client Error: Forbidden for url: https://gitlab.com/api/v4/user",
info: "",
result: null,
data: null
}
I believe I have all the necessary gitlab permissions and can't figure out what I'm doing wrong.
I think that in this case we can just use the OIDC endpoint to fetch userinfo. For gitlab it is: ttps://gitlab.com/oauth/userinfo. Therefore, you do not need api scope, just openid email profile
So the following configuration actually works for me:
AUTHENTICATION_SOURCES = ['oauth2', 'internal']
OAUTH2_CONFIG = [
{
'OAUTH2_NAME': 'gitlab',
'OAUTH2_DISPLAY_NAME': 'Gitlab',
'OAUTH2_CLIENT_ID': 'my-client-id-here',
'OAUTH2_CLIENT_SECRET': 'my-client-secret-here',
'OAUTH2_TOKEN_URL': 'https://gitlab.com/oauth/token',
'OAUTH2_AUTHORIZATION_URL': "https://gitlab.com/oauth/authorize",
'OAUTH2_API_BASE_URL': 'https://gitlab.com/oauth/',
'OAUTH2_USERINFO_ENDPOINT': 'userinfo',
'OAUTH2_SCOPE': 'openid email profile',
'OAUTH2_ICON': 'fa-gitlab',
'OAUTH2_BUTTON_COLOR': '#E24329',
}
]
OAUTH2_AUTO_CREATE_USER = True

How to access Namespaced JWT Claims in AWS HTTP API Gateway Request Mapping

I'm trying to set up HTTP integration in AWS API Gateway v2 (aka HTTP API). In my config, I have a native JWT authorizer and want to append one namespaced JWT access_token claims to HTTP request headers.
As long as claims as simple name such as sub or iss this is working fine with the following mapping syntax:
append:header.simple = append:$context.authorizer.claims.simple
However, some of my claims are namespace with an https://namespace/ prefix (is a requirement from Auth0 and cannot be changed). This is where mapper syntax is falling short for me.
Say my input JWT is like this:
{
"aud": "my.dev.api",
"azp": "CCCC",
"exp": "1610606942",
"https://my.ns/account_no": "100368421",
"iat": "1610598342",
"iss": "https://mytenant.auth0.com/",
"scope": "openid profile email account:admin",
"sub": "auth0|user-id"
}
How can I map namespaced claim https://my.ns/account_no?
I tried $context.authorizer.claims['https://my.ns/account_no'] with no luck. Here is the terraform setup I use:
resource "aws_apigatewayv2_integration" "root" {
api_id = aws_apigatewayv2_api.api.id
integration_type = "HTTP_PROXY"
connection_type = "INTERNET"
description = "This is our GET / integration"
integration_method = "GET"
integration_uri = "http://${aws_lb.ecs_lb.dns_name}"
passthrough_behavior = "WHEN_NO_MATCH"
request_parameters = {
"append:header.account_no" = "$context.authorizer.claims['https://my.ns/account_no']" <-- FAILING HERE
}
}
Error I'm getting in terraform and dashboard is the same:
Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: $context.authorizer.claims["https://my.ns/account_no"]]
Thanks for your assistance.

Spring OAuth2 Keycloak Kubernetes internal/external access

I have Keycloak (10.0.3) server configured inside a Kubernetes Cluster.
The keycloak server has to handle authentification for external user (using an external url) and also handle oauth2 token for Spring microservices communications.
Then web application spring services uses oidc providers :
spring:
security:
oauth2:
client:
provider:
oidc:
issuer-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm
authorization-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm/protocol/openid-connect/auth
jwk-set-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm/protocol/openid-connect/certs
token-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm/protocol/openid-connect/token
user-name-attribute: preferred_username
The external URL of keycloak is https://keycloak.localhost, managed by ingress redirection handled by Traefik v2
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: keycloak-https
namespace: keycloak-cluster
annotations:
traefik.frontend.passHostHeader: "true"
spec:
entryPoints:
- websecure
routes:
- match: Host(`keycloak.localhost`)
kind: Rule
services:
- name: keycloak-cluster-http
port: 80
tls:
options:
name: mytlsoption
namespace: traefik
store:
name: default
I can access Keycloak using https://keycloak.localhost, no problem, it works.
The problem is that when I try to access my web application, it will always redirect to 'http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm', which is not resolved outside k8s.
If I change issuer-uri to http://keycloak.localhost then it doesn't work as keycloak.locahost is not resolved inside k8s.
I tried to set the KEYCLOAK_FRONTEND_URL to https://keycloak.localhost/auth, but no change.
Please, does someone has the same kind of settings and managed to make it working ?
Best regards
Managed to fix it using coredns and adding a rewrite rule... :
rewrite name keycloak.localhost keycloak-cluster-http.keycloak-cluster.svc.cluster.local
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
rewrite name keycloak.localhost keycloak-cluster-http.keycloak-cluster.svc.cluster.local
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
The authorization_uri needs to be understood by the browser since that URI is processed in the front channel. The rest of the URIs are processed in the back channel.
Because of that, the authorization_uri should use the front channel way of addressing the authorization server:
authorization_uri: https://keycloak.localhost/auth/realms/myrealm/protocol/openid-connect/auth
EDIT Based on Joe Grandja's input below, it appears that it's also necessary to not specify the issuer-uri property. The issuer-uri property is a shortcut for specifying the other URIs, and since you are specifying those, you don't need it anyway.
Here A POC that helped me with the issue.
Similar configuration ,keycloak and spring gateway are in kubernetes
The external user uses keycloak external host with https protocol
https://external-https/auth/realms/myrealm/protocol/openid-connect/auth?...
The ingress break the https and moves it to http + change the host to internal-http
gateway uses internal-http to connect to keycloakon port 8080
In order for the issuer to be the same protocol as the external the configuration uses https in user-info-uri and authorization-uri but the rest are http
make sure that the keycloak pod is open for https connection (8443)
authorization-uri: https://internal-http:8443/auth/realms/myrealm/protocol/openid-connect/auth
user-info-uri: https://internal-http:8443/auth/realms/myrealm/protocol/openid-connect/userinfo
issuer-uri: http://internal-http:8080/auth/realms/myrealm
To fix the host part of the issuer
In the gateway code I updated the following based on https://github.com/spring-projects/spring-security/issues/8882#user-content-oauth2-client
#SneakyThrows
private WebClient webClient() {
SslContext sslContext = SslContextBuilder
.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
HttpClient httpClient = HttpClient.create()
.secure(t -> t.sslContext(sslContext))
.wiretap(true)
;
ReactorClientHttpConnector conn = new ReactorClientHttpConnector(httpClient);
return WebClient.builder()
.defaultHeader("HOST", "external-https")
.clientConnector(conn)
.build();
}
#Bean
WebClientReactiveAuthorizationCodeTokenResponseClient webClientReactiveAuthorizationCodeTokenResponseClient() {
final WebClientReactiveAuthorizationCodeTokenResponseClient webClientReactiveAuthorizationCodeTokenResponseClient = new WebClientReactiveAuthorizationCodeTokenResponseClient();
final WebClient webClient = webClient();
webClientReactiveAuthorizationCodeTokenResponseClient.setWebClient(webClient);
return webClientReactiveAuthorizationCodeTokenResponseClient;
}
#Bean
WebClientReactiveClientCredentialsTokenResponseClient webClientReactiveClientCredentialsTokenResponseClient() {
final WebClientReactiveClientCredentialsTokenResponseClient webClientReactiveClientCredentialsTokenResponseClient = new WebClientReactiveClientCredentialsTokenResponseClient();
final WebClient webClient = webClient();
webClientReactiveClientCredentialsTokenResponseClient.setWebClient(webClient);
return webClientReactiveClientCredentialsTokenResponseClient;
}
#Bean
WebClientReactiveRefreshTokenTokenResponseClient webClientReactiveRefreshTokenTokenResponseClient() {
final WebClientReactiveRefreshTokenTokenResponseClient webClientReactiveRefreshTokenTokenResponseClient = new WebClientReactiveRefreshTokenTokenResponseClient();
final WebClient webClient = webClient();
webClientReactiveRefreshTokenTokenResponseClient.setWebClient(webClient);
return webClientReactiveRefreshTokenTokenResponseClient;
}
#Bean
WebClientReactivePasswordTokenResponseClient webClientReactivePasswordTokenResponseClient() {
final var client = new WebClientReactivePasswordTokenResponseClient();
final WebClient webClient = webClient();
client.setWebClient(webClient);
return client;
}
#Bean
DefaultReactiveOAuth2UserService reactiveOAuth2UserService() {
final DefaultReactiveOAuth2UserService userService = new DefaultReactiveOAuth2UserService();
final WebClient webClient = webClient();
userService.setWebClient(webClient);
return userService;
}
Disabled the certificate validation - the connection is only between keycloak and gateway , both are in the kubernetes and otherwise would have used http connection, if not for this issue
The host part tells the keyclock what is the host to use for the issuer
Another issue encountered is that the location return when redirecting to authentication contains the internal url and not the external which the outside world doesn't know of
For that ,update the location that returns from the gateway
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http)
...
oauth2Login(oAuth2LoginSpec -> oAuth2LoginSpec
...
.addFilterAfter(new LoginLocationFilter("external-https"), SecurityWebFiltersOrder.LAST)
...
public class LoginLocationFilter implements WebFilter {
private final String externalUrl;
public LoginLocationFilter(String externalUrl) {
this.externalUrl = externalUrl;
}
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
//before commit ,otherwise the headers will be read only
exchange.getResponse().beforeCommit(() -> {
fixLocation(exchange);
return Mono.empty();
});
return chain.filter(exchange);
}
...

How do I connect a specific path on an AWS API Gateway to a specific ECS instance via Terraform?

I'm running an application in AWS ECS successfully behind a network load balancer, and able to access it via the internet. I'm trying to put it behind an API Gateway (with the eventual goal of making the VPC private so services can ONLY be accessed via the API Gateway). The thing I'm having trouble with is the best way to specify the service in the aws_api_gateway_integration configuration.
I can access the service successfully via the NLB. I've tried putting the URI into the aws_api_gateway_integration but it doesn't work for access, and probably isn't the best way to specify it since the DNS name will change. I'm unable to find any examples of API Gateway with ECS.
ECS Service Definition:
resource "aws_ecs_service" "cocktail-service-service" {
name = "${var.prefix}-cocktail-service-service"
cluster = "${aws_ecs_cluster.ecs-cluster.id}"
task_definition = "${aws_ecs_task_definition.cocktail-service.family}:${max("${aws_ecs_task_definition.cocktail-service.revision}", "${data.aws_ecs_task_definition.cocktail-service.revision}")}"
desired_count = 1
network_configuration {
security_groups = ["${aws_security_group.ecs-public-sg.id}"]
subnets = ["${aws_subnet.dev-vpc-subnet-1.id}", "${aws_subnet.dev-vpc-subnet-2.id}"]
}
load_balancer {
target_group_arn = "${aws_lb_target_group.ecs-target-group.arn}"
container_port = 8080
container_name = "cocktail-service"
}
}
API Gateway definitions:
resource "aws_api_gateway_resource" "cocktail-service-resource" {
rest_api_id = "${aws_api_gateway_rest_api.dev-api-gateway.id}"
parent_id = "${aws_api_gateway_rest_api.dev-api-gateway.root_resource_id}"
# path_part appears to be how to trigger catching the request
path_part = "cocktails"
}
resource "aws_api_gateway_method" "cocktail-service-method" {
rest_api_id = "${aws_api_gateway_rest_api.dev-api-gateway.id}"
resource_id = "${aws_api_gateway_resource.cocktail-service-resource.id}"
http_method = "GET"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "cocktail-service-integration" {
rest_api_id = "${aws_api_gateway_rest_api.dev-api-gateway.id}"
resource_id = "${aws_api_gateway_resource.cocktail-service-resource.id}"
http_method = "${aws_api_gateway_method.cocktail-service-method.http_method}"
type = "HTTP"
uri = "http://load-balancer-name-goes-here.elb.us-east-2.amazonaws.com/cocktails"
integration_http_method = "GET"
# TODO: change connection_type to VPC_LINK once the VPC is private
connection_type = "INTERNET"
#connection_id = "${aws_api_gateway_vpc_link.test.id}"
}
When I try to test this through the API Gateway console Test tool, I get a 500 internal server error.

Fiware Orion - pepProxy

i'm part of a team that is developing an application that uses the Fiware GE's has part of the Smart-AgriFood accelerator.
We are using the Orion Context Broker for gathering the data provided by the sensor network, and we intend to use the Pep-Proxy to authenticate the sensor node for access the Orion instance. We have tried the following pepProxy's:
https://github.com/telefonicaid/fiware-orion-pep
https://github.com/ging/fi-ware-pep-proxy
We only have success implementing the second (fi-ware-pep-proxy) implementation of the proxy. With the fiware-orion-pep we haven't been able to connect to the Keystone Global instance (account.lab.fi-ware.org), we have tried the account.lab... and the cloud.lab..., my question are:
1) is the keystone (IDM) instance for authentication the account.lab or the cloud.lab?? and what port's to use or address's?
2) is the fiware-orion-pep prepared for authenticate at the account.lab.fi-ware.org?? here is way i ask this:
This one works with the curl command at >> cloud.lab.fiware.org:4730/v2.0/tokens
{
"auth": {
"passwordCredentials": {
"username": "<my_user>",
"password": "<my_password>"
}
}
}'
This one does't work with the curl comand at >> account.lab.fi-ware.org:5000/v3/auth/tokens
{
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"domain": {
"name": "<my_domain>"
},
"name": "<my_user>",
"password": "<my_password>"
}
}
}
} }'
3) what is the implementation that i should be using for authenticate the devices or other calls to the Orion instance???
Here are the configuration that i used:
fiware-orion-pep
config.authentication = {
checkHeaders: true,
module: 'keystone',
user: '<my_user>',
password: '<my_password>',
domainName: '<my_domain>',
retries: 3,
cacheTTLs: {
users: 1000,
projectIds: 1000,
roles: 60
},
options: {
protocol: 'http',
host: 'account.lab.fiware.org',
port: 5000,
path: '/v3/role_assignments',
authPath: '/v3/auth/tokens'
}
};
fi-ware-pep-proxy (this one works), i have set the listing port to 1026 at the source code
var config = {};
config.account_host = 'https://account.lab.fiware.org';
config.keystone_host = 'cloud.lab.fiware.org';
config.keystone_port = 4731;
config.app_host = 'localhost';
config.app_port = '10026';
config.username = 'pepProxy';
config.password = 'pepProxy';
// in seconds
config.chache_time = 300;
config.check_permissions = false;
config.magic_key = undefined;
module.exports = config;
Thanks in advance for the time ... :)
The are currently some differences in how both PEP Proxies authenticate and validate against the global instances, so they do not behave in exactly the same way.
The one in telefonicaid/fiware-orion-pep was developed to fulfill the PEP Proxy requirements (authentication and validation against a Keystone and Access Control) in individual projects with their own Keystone and Keypass (a flavour of Access Control) installations, and so it evolved faster than the one in ging/fi-ware-pep-proxy and in a slightly different direction. As an example, the former supports multitenancy using the fiware-service and fiware-servicepath headers, while the latter is transparent to those mechanisms. This development direction meant also that the functionality slightly differs from time to time from the one in the global instance.
That being said, the concrete answer:
- Both PEP Proxies should be able to contact the global instance. If one doesn't, please, fill a bug in the issues of the Github repository and we will fix it as soon as possible.
- The ging/fi-ware-pep-proxy was specifically designed for accessing the global instance, so you should be able to use it as expected.
Please, if you try to proceed with the telefonicaid/fiware-orion-pep take note also that:
- the configuration flag authentication.checkHeaders should be false, as the global instance does not currently support multitenancy.
- current stable release (0.5.0) is about to change to next version (probably today) so maybe some of the problems will solve with the update.
Hope this clarify some of your doubts.
[EDIT]
1) I have already install the telefonicaid/fiware-orion-pep (v 0.6.0) from sources and from the rpm package created following the tutorial available in the github. When creating the rpm package, this is created with the following name pep-proxy-0.4.0_next-0.noarch.rpm.
2) Here is the configuration that i used:
/opt/fiware-orion-pep/config.js
var config = {};
config.resource = {
original: {
host: 'localhost',
port: 10026
},
proxy: {
port: 1026,
adminPort: 11211
} };
config.authentication = {
checkHeaders: false,
module: 'keystone',
user: '<##################>',
password: '<###################>',
domainName: 'admin_domain',
retries: 3,
cacheTTLs: {
users: 1000,
projectIds: 1000,
roles: 60
},
options: { protocol: 'http',
host: 'cloud.lab.fiware.org',
port: 4730,
path: '/v3/role_assignments',
authPath: '/v3/auth/tokens'
} };
config.ssl = {
active: false,
keyFile: '',
certFile: '' }
config.logLevel = 'DEBUG'; // List of component
config.middlewares = {
require: 'lib/plugins/orionPlugin',
functions: [
'extractCBAction'
] };
config.componentName = 'orion';
config.resourceNamePrefix = 'fiware:';
config.bypass = false;
config.bypassRoleId = '';
module.exports = config;
/etc/sysconfig/pepProxy
# General Configuration
############################################################################
# Port where the proxy will listen for requests
PROXY_PORT=1026
# User to execute the PEP Proxy with
PROXY_USER=pepproxy
# Host where the target Context Broker is located
# TARGET_HOST=localhost
# Port where the target Context Broker is listening
# TARGET_PORT=10026
# Maximum level of logs to show (FATAL, ERROR, WARNING, INFO, DEBUG)
LOG_LEVEL=DEBUG
# Indicates what component plugin should be loaded with this PEP: orion, keypass, perseo
COMPONENT_PLUGIN=orion
#
# Access Control Configuration
############################################################################
# Host where the Access Control (the component who knows the policies for the incoming requests) is located
# ACCESS_HOST=
# Port where the Access Control is listening
# ACCESS_PORT=
# Host where the authentication authority for the Access Control is located
# AUTHENTICATION_HOST=
# Port where the authentication authority is listening
# AUTHENTICATION_PORT=
# User name of the PEP Proxy in the authentication authority
PROXY_USERNAME=XXXXXXXXXXXXX
# Password of the PEP Proxy in the Authentication authority
PROXY_PASSWORD=XXXXXXXXXXXXX
In the files above i have tried the following parameters:
Keystone instance: account.lab.fiware.org or cloud.lab.fiware.org
User: pep or pepProxy or "user from fiware account"
Pass: pep or pepProxy or "user password from account"
Port: 4730, 4731, 5000
The result it's the same as before... the telefonicaid/fiware-orion-pep is unable to authenticate:
log file at /var/log/pepProxy/pepProxy
time=2015-04-13T14:49:24.718Z | lvl=ERROR | corr=71a34c8b-10b3-40a3-be85-71bd3ce34c8a | trans=71a34c8b-10b3-40a3-be85-71bd3ce34c8a | op=/v1/updateContext | msg=VALIDATION-GEN-003] Error connecting to Keystone authentication: KEYSTONE_AUTHENTICATION_ERROR: There was a connection error while authenticating to Keystone: 500
time=2015-04-13T14:49:24.721Z | lvl=DEBUG | corr=71a34c8b-10b3-40a3-be85-71bd3ce34c8a | trans=71a34c8b-10b3-40a3-be85-71bd3ce34c8a | op=/v1/updateContext | msg=response-time: 50745 statusCode: 500
result from the client console
{
"message": "There was a connection error while authenticating to Keystone: 500",
"name": "KEYSTONE_AUTHENTICATION_ERROR"
}
I'm doing something wrong here??