CloudRun: Debug authentication error from curl - kubernetes

I am spinning up a container (pod/Job) from a GKE.
I have set up the appropriate Service Account on the cluster's VMs.
Therefore, when I manually perform a curl to a specific CloudRun service endpoint, I can perform the request (and get authorized and have 200 in my response)
However, when I try to automate this by setting an image to run in a Job as follows, I get 401
- name: pre-upgrade-job
image: "google/cloud-sdk"
args:
- curl
- -s
- -X
- GET
- -H
- "Authorization: Bearer $(gcloud auth print-identity-token)"
- https://my-cloud-run-endpoint
Here are the logs on Stackdriver
{
httpRequest: {
latency: "0s"
protocol: "HTTP/1.1"
remoteIp: "gdt3:r787:ff3:13:99:1234:avb:1f6b"
requestMethod: "GET"
requestSize: "313"
requestUrl: "https://my-cloud-run-endpoint"
serverIp: "212.45.313.83"
status: 401
userAgent: "curl/7.59.0"
}
insertId: "29jdnc39dhfbfb"
logName: "projects/my-gcp-project/logs/run.googleapis.com%2Frequests"
receiveTimestamp: "2019-09-26T16:27:30.681513204Z"
resource: {
labels: {
configuration_name: "my-cloud-run-service"
location: "us-east1"
project_id: "my-gcp-project"
revision_name: "my-cloudrun-service-d5dbd806-62e8-4b9c-8ab7-7d6f77fb73fb"
service_name: "my-cloud-run-service"
}
type: "cloud_run_revision"
}
severity: "WARNING"
textPayload: "The request was not authorized to invoke this service. Read more at https://cloud.google.com/run/docs/securing/authenticating"
timestamp: "2019-09-26T16:27:30.673565Z"
}
My question is how can I see if an "Authentication" header does reach the endpoint (the logs do not enlighten me much) and if it does, whether it is appropriately rendered upon image command/args invocation.

In your job you use this container google/cloud-sdk which is a from scratch installation of gcloud tooling. It's generic, without any customization.
When you call this $(gcloud auth print-identity-token) you ask for the identity token of the service account configured in the gcloud tool.
If we put together this 2 paragraphs, you want to generate an identity token from a generic/blank installation of gcloud tool. By the way, you don't have defined service account in your gcloud and your token is empty (like #johnhanley said).
For solving this issue, add an environment variable like this
env:
- GOOGLE_APPLICATION_CREDENTIAL=<path to your credential.json>
I don't know where is your current credential.json of your running environment. Try to perform an echo of this env var to find it and forward it correctly to your gcloud job.
If you are on compute engine or similar system compliant with metadata server, you can get a correct token with this command:
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=<URL of your service>"
UPDATE
Try to run your command outside of the gcloud container. Here the update of your job
- name: pre-upgrade-job
image: "google/cloud-sdk"
entrypoint: "bash"
args:
- -c
- "curl -s -X GET -H \"Authorization: Bearer $(gcloud auth print-identity-token)\" https://my-cloud-run-endpoint"
Not sure that works. Let me know

In your Job, gcloud auth print-identity-token likely does not return any tocken.
The reason is that locally, gcloud uses your identity to mint a token, but in a Job, you are not logged into gcloud.

Related

Keycloak: All API response with 404

I followed this tutorial to setup Keycloak and create user but the response for the step of Generating Access Tokens With Keycloak's API 404. I'm using Keycloak version 18.0.0
In the logs of keycloak I found this error
2022-06-12 23:59:57,177 DEBUG [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-3) Error response 404: javax.ws.rs.NotFoundException: RESTEASY003210: Could not find resource for full path: http://localhost:8080/auth/realms/test/protocol/openid-connect/token
From keycloak 17+ there are changes in resource or token URIs. Try removing auth from your request URL.
If you are using Keycloak version < 17
curl -k -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=your-client" -d "username=some-user" -d "password=hardpassword" -d "grant_type=password" -X POST http://localhost:8080/auth/realms/yourrealm/protocol/openid-connect/token
If you are using Keycloak version > 17
curl -k -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=your-client" -d "username=some-user" -d "password=hardpassword" -d "grant_type=password" -X POST http://localhost:8080/realms/yourrealm/protocol/openid-connect/token
You did set in Headers instead of Body.
Move the Key & Values to Body.
You can verify Token URL by click "OpenID Endpoint Configuration" link
It will show Token URL

Localstack: which port to use for ES rest api

I am using docker to run Localstack and image 0.11.1.
I turned on es service and exposed port 4566 - as according to the doc (https://github.com/localstack/localstack):
Starting with version 0.11.0, all APIs are exposed via a single edge service, which is accessible on http://localhost:4566 by default
I could successfully use AWS CLI to list domain names and create ones:
aws --endpoint-url=http://localhost:4566 es list-domain-names
aws --endpoint-url=http://localhost:4566 es create-elasticsearch-domain --domain-name my-domain --elasticsearch-version 7.4
But when I tried to index document
curl -XPUT http://localhost:4566/my-domain/_doc/1 -d '{"hello": "World"}' -H 'Content-Type: application/json'
it returned {"status": "running"} reponse to me and I saw the message in logs:
INFO:localstack.services.edge: Unable to find forwarding rule for host "localhost:4566", path "/my-domain/_doc/1", target header "", auth header ""
Then I added port 4571 to exposed ports by configuring it in docker-compose.yml and tried the same, but using http://localhost:4571/my-domain/_doc/1 url this time to index document.
curl -XPUT http://localhost:4571/my-domain/_doc/1 -d '{"hello": "World"}' -H 'Content-Type: application/json'
It worked.
I don't understand - according to the doc I should only use port 4566 but it does not work.
Am I missing something?
My docker-compose.yml with both ports exposed:
...
localstack:
container_name: "localstack"
image: localstack/localstack:0.11.1
privileged: true
ports:
- "4566:4566"
- "4571:4571"
environment:
- SERVICES=es
- START_WEB=0
- LAMBDA_REMOTE_DOCKER=0
- DATA_DIR=/tmp/localstack/data
...
From here, you can see this table:
Parameter
Description
Default
service.edgePort
Port number for Localstack edge service
4566
service.esPort
Port number for Localstack elasticsearch service
4571

Why isn't the request body showing up in the Kubernetes API server audit log?

I have added the following command-line arguments to kube-apiserver to enable audit logging:
- --audit-log-path=/tmp/k8s-audit.log
- --audit-policy-file=/etc/kubernetes/audit.yaml
- --audit-log-maxage=1
- --audit-log-maxsize=100
- --audit-log-maxbackup=1
The contents of /etc/kubernetes/audit.yaml is:
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- "ResponseStarted"
- "ResponseComplete"
rules:
- level: RequestResponse
I have run a command with verbose logging, so that I can see the request body:
$ kubectl --v=10 uncordon cluster-worker2
And the kubectl command logs the request body as follows:
I0328 09:00:07.591869 47228 request.go:942] Request Body: {"spec":{"unschedulable":null}}
But I don't see this request body anywhere in the audit log file on the kubernetes server. What's wrong with my configuration?
The request is actually only logged in the ResponseComplete stage, somewhat unexpectedly. Even though Kubernetes could theoretically log the request as soon as it receives it, it doesn't.
So it's necessary to remove the ResponseComplete line from the omitstages in the policy configuration file (audit.yaml).

Keycloak-gatekeeper: 'aud' claim and 'client_id' do not match

What is the correct way to set the aud claim to avoid the error below?
unable to verify the id token {"error": "oidc: JWT claims invalid: invalid claims, 'aud' claim and 'client_id' do not match, aud=account, client_id=webapp"}
I kinda worked around this error message by hardcoding aud claim to be the same as my client_id. Is there any better way?
Here is my docker-compose.yml:
version: '3'
services:
keycloak-proxy:
image: "keycloak/keycloak-gatekeeper"
environment:
- PROXY_LISTEN=0.0.0.0:3000
- PROXY_DISCOVERY_URL=http://keycloak.example.com:8181/auth/realms/realmcom
- PROXY_CLIENT_ID=webapp
- PROXY_CLIENT_SECRET=0b57186c-e939-48ff-aa17-cfd3e361f65e
- PROXY_UPSTREAM_URL=http://test-server:8000
ports:
- "8282:3000"
command:
- "--verbose"
- "--enable-refresh-tokens=true"
- "--enable-default-deny=true"
- "--resources=uri=/*"
- "--enable-session-cookies=true"
- "--encryption-key=AgXa7xRcoClDEU0ZDSH4X0XhL5Qy2Z2j"
test-server:
image: "test-server"
With recent keycloak version 4.6.0 the client id is apparently no longer automatically added to the audience field 'aud' of the access token.
Therefore even though the login succeeds the client rejects the user.
To fix this you need to configure the audience for your clients (compare doc [2]).
Configure audience in Keycloak
Add realm or configure existing
Add client my-app or use existing
Goto to the newly added "Client Scopes" menu [1]
Add Client scope 'good-service'
Within the settings of the 'good-service' goto Mappers tab
Create Protocol Mapper 'my-app-audience'
Name: my-app-audience
Choose Mapper type: Audience
Included Client Audience: my-app
Add to access token: on
Configure client my-app in the "Clients" menu
Client Scopes tab in my-app settings
Add available client scopes "good-service" to assigned default client scopes
If you have more than one client repeat the steps for the other clients as well and add the good-service scope.
The intention behind this is to isolate client access. The issued access token will only be valid for the intended audience.
This is thoroughly described in Keycloak's documentation [1,2].
Links to recent master version of keycloak documentation:
[1] https://github.com/keycloak/keycloak-documentation/blob/master/server_admin/topics/clients/client-scopes.adoc
[2] https://github.com/keycloak/keycloak-documentation/blob/master/server_admin/topics/clients/oidc/audience.adoc
Links with git tag:
[1] https://github.com/keycloak/keycloak-documentation/blob/f490e1fba7445542c2db0b4202647330ddcdae53/server_admin/topics/clients/oidc/audience.adoc
[2] https://github.com/keycloak/keycloak-documentation/blob/5e340356e76a8ef917ef3bfc2e548915f527d093/server_admin/topics/clients/client-scopes.adoc
This is due to a bug: https://issues.jboss.org/browse/KEYCLOAK-8954
There are two workarounds described in the bug report, both of which appear to do basically the same thing as the accepted answer here but can be applied to the Client Scope role, so you don't have to apply them to every client individually.
If, like me, you want to automate the keycloak config, you can use kcadm
/opt/jboss/keycloak/bin/kcadm.sh \
create clients/d3170ee6-7778-413b-8f41-31479bdb2166/protocol-mappers/models -r your-realm \
-s name=audience-mapping \
-s protocol=openid-connect \
-s protocolMapper=oidc-audience-mapper \
-s config.\"included.client.audience\"="your-audience" \
-s config.\"access.token.claim\"="true" \
-s config.\"id.token.claim\"="false"
Its works to me:
In my SecurityConfiguration class:
#Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
config.setAllowedMethods(Arrays.asList(CorsConfiguration.ALL));
config.setAllowedHeaders(Arrays.asList(CorsConfiguration.ALL));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return source;
}

JENKINS Authentication Fails

I am getting the following error while trying to trigger Jenkins job from any REST Client
Authentication required
<!-- You are authenticated as: anonymous
Groups that you are in:
Permission you need to have (but didn't):
hudson.model.Hudson.Read
... which is implied by: hudson.security.Permission.GenericRead
... which is implied by: hudson.model.Hudson.Administer
-->
</body> </html>
The request is getting triggered while using curl from terminal
I am using the following syntax
http://user:apiToken#jenkins.yourcompany.com/job/your_job/build?token=TOKEN
[ref :https://wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients]
ie. curl -X POST http://user:apiToken#jenkins.yourcompany.com/job/your_job/build?token=TOKEN
Check this "This build is parameterized " , select the credentials parameter from drop down.
Use this
curl -X POST http://jenkins.rtcamp.com/job/Snapbox/buildWithParameters --user "username:password"
It solved my authentication problem.
I hope it will help others too.
My development team's configuration settings were matrix-based security so I had to find my group and give my group workspace access.
1.Click on Manage Jenkins .
2.Click on Configure Global Security .
3.in matrix-based security change:
Overall - Read
Job - Build
Job - Read
Job - Workspace
Then
POST jobUrl/buildWithParameters HTTP/1.1
Host: user:token
Authorization: Basic dWdlbmxpazo4elhjdmJuTQ==
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
Branch=develop
For me
https://user:password#jenkins.mycompany.org/job/job_name/build?token=my_token
in https://jenkins.mycompany.org/configureSecurity
disable CORS
hope this help
Try using the -u parameter to specify the credentials:
curl -u user:apiToken -X POST http://jenkins.yourcompany.com/job/your_job/build?token=TOKEN
I provided header Authorization parameter with value :
BASIC base_64encoded(username:password) and it worked fine.
Authorization Basic bmltbWljdjpqZX*********
Simply disable "CSRF Protection" in the global Security Options, because those URLs don't send post data identification.
focal point :
username:password#
curl -u user:apiToken -X POST http://username:password#jenkins.yourcompany.com/job/your_job/build?key1=value1&key2=value2 ...
If you are encountering this problem with jenkins api client in ruby.
I figured Jenkins is blocking all the get request, instead use api_post_request.
Also, you have to generate api token because normal password is not working anymore.
#client = JenkinsApi::Client.new(
server_url: "",
username: '',
password: ""
)
SITE_FILE_PATH = 'artifact/target/site'.freeze
#jenkins_uri=''
#jenkins_job_name=''
def latest_test_file_path
"/job/#{#jenkins_job_name}/job/master/lastSuccessfulBuild/#{SITE_FILE_PATH}/Test-Results/test-results.html"
end
puts #client.api_post_request(latest_test_file_path,{},true).body
you can set the parameter true if you want the raw response.
default parameter or passing false will just return response code.
Also make sure to construct the right prefix.
You can refer to the above snipped.