Implement Envoy OAuth2 filter with disabled routes - oauth-2.0

I deployed an envoy as a side car to manage oauth2. Everything work fine for all the resources and the client is redirected to the OIDC in order to authenticate.
Here is a part of my conf (managed in a Helm chart):
- name: envoy.filters.network.http_connection_manager
typed_config:
"#type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
access_log:
- name: envoy.access_loggers.file
typed_config:
"#type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: /dev/stdout
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: my-service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: my-service
http_filters:
- name: envoy.filters.http.oauth2
typed_config:
"#type": type.googleapis.com/envoy.extensions.filters.http.oauth2.v3.OAuth2
config:
token_endpoint:
cluster: {{ .Values.back.envoy.oidc.name }}
uri: https://{{ .Values.back.envoy.oidc.address }}/oidc/token
timeout: 5s
authorization_endpoint: https://{{ .Values.back.envoy.oidc.address }}/oidc/authorize
redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/oidc/callback"
redirect_path_matcher:
path:
exact: /oidc/callback
signout_path:
path:
exact: /oidc/signout
credentials:
client_id: {{ required "back.envoy.oidc.client_id is required" .Values.back.envoy.oidc.client_id }}
token_secret:
name: token
sds_config:
resource_api_version: V3
path: "/etc/envoy/token-secret.yaml"
hmac_secret:
name: hmac
sds_config:
resource_api_version: V3
path: "/etc/envoy/hmac-secret.yaml"
forward_bearer_token: true
# (Optional): defaults to 'user' scope if not provided
auth_scopes:
- user
- openid
- email
- homelan_devices_read
- homelan_topology_read
- homelan_devices_write
# (Optional): set resource parameter for Authorization request
#resources:
#- oauth2-resource
#- http://example.com
- name: envoy.filters.http.router
typed_config: {}
Now I'd like that some of the exposed resources don't need to be authenticated.
I see in the doc the Oauth filter doc "Leave this empty to disable OAuth2 for a specific route, using per filter config." (see https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/oauth2/v3/oauth.proto#envoy-v3-api-msg-extensions-filters-http-oauth2-v3-oauth2config)
This phrase make me think that it may be possible.
I tried to manage it changing my conf throught virtual_hosts this way :
virtual_hosts:
- name: no-oauth
domains: ["*"]
typed_per_filter_config:
envoy.filters.http.oauth2:
"#type": type.googleapis.com/envoy.extensions.filters.http.oauth2.v3.OAuth2
routes:
- match:
prefix: "/api/v1/myResource1"
route:
cluster: my-service
- name: my-service
domains: ["*"]
routes:
- match:
prefix: "/api/v1/myResource2"
route:
cluster: my-service
I have the error : [critical][main] [source/server/server.cc:117] error initializing configuration '/etc/envoy/envoy.yaml': The filter envoy.filters.http.oauth2 doesn't support virtual host-specific configurations
Any idea ? Did someone implement Envoy OAuth2 filter with disabled routes ?

After looking at my envoy logs, I realized that path is know as header ":path".
The pass_through_matcher math the header.
Then only adding:
pass_through_matcher:
- name: ":path"
prefix_match: "/healthz"
- name: ":path"
prefix_match: "/api/v1/myResource1"
in my conf without the lua filter (see my previous answer) it works.

For information, I found a workaround:
I added a LUA filter before my OAuth2 one:
- name: envoy.filters.http.lua
typed_config:
"#type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inline_code: |
function envoy_on_request(request_handle)
request_handle:headers():add("X-Path", request_handle:headers():get(":path"))
end
In order to add the path in a header.
Then I can use this element of conf Oauth2:
pass_through_matcher
(repeated config.route.v3.HeaderMatcher) Any request that matches any of the provided matchers will be passed through without OAuth validation.
So I add this to my OAuth2 filter:
pass_through_matcher:
- name: "X-path"
prefix_match: "/healthz"
- name: "X-path"
prefix_match: "/api/v1/myResource1"
Then my /api/v1/myResource1 requests (and healthz also) don't need authentication (are disable from the OAuth2) while my /api/v1/myResource2 requests need it.
I still have got the unanswered question:
What do the OAuth filter doc means with :"Leave this empty to disable OAuth2 for a specific route, using per filter config."

Related

Bitbucket Cloud interceptor for Tekton EventListener

I'm creating an eventlisterner for my repo on Bitbucket Cloud and saw on the curent example on the Tekton documentation that the Bitbucket interceptor only support Bitbucket Server.
I've created the eventlistener and looks like this:
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: bitbucket-el
spec:
serviceAccountName: tekton-triggers-admin
triggers:
- name: bitbucket-triggers
interceptors:
- bitbucket:
secretRef:
secretName: bitbucket-secret
secretKey: secretToken
eventTypes:
- cel:
filter: "header.match('X-Event-Key', 'repo:push')"
overlays:
- key: extensions.tag_name
expression: "split(body.ref, '/')[2]"
- key: extensions.mangledtag
expression: "split(split(body.ref, '/')[2], '.')[0]+'-'+split(split(body.ref, '/')[2], '.')[1]+'-'+split(split(body.ref, '/')[2], '.')[2]"
bindings:
- ref: bitbucket-binding
template:
ref: bitbucket-template
and I pass it the token generated (bitbucket-secret) from Bitbucket Cloud consumer secret by going through this doc: https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/
I used basic auth on Ingress and the webhook return 401 Unauthorized and now after I remove the basic auth and then trigger the webhook with a push I'm seeing 403 Forbiden.
Check the image below for illustartion:
enter image description here
Thank you in advance
I spend alot of time on this issue and finally fixed it by using the CEL expression interceptors, as follows.
In this Trigger, we are using the overlays to add the "X-Hub-Signature" to the body of the payload, where the expression value i.e., 1234567 doesn't matter it can be anything, we are just adding the HMAC to the body so that we will not get an error.
Note: By default, there is no interceptor for the bitbucket CLOUD
apiVersion: triggers.tekton.dev/v1beta1
kind: Trigger
metadata:
name: energy
spec:
serviceAccountName: pipeline
interceptors:
- ref:
name: "cel"
params:
- name: "filter"
value: "header.match('X-Event-Key', 'repo:push')"
- name: "overlays"
value:
- key: X-Hub-Signature
expression: "1234567"
bindings:
- ref: energy
template:
ref: energy
I am trying to achieve the same, starting a build when a PR merge has been done in BitBucket cloud.
I was able to create the EventListener resource, but my pipeline is not triggered after merging a PR.
Looking at your example, I still have some questions
How is the GIT repository and the secret configured?
How can you specify a specific branch?
I was looking for a complete example but it seems like Tekton is just ignoring Bitbucket Cloud as a VCS ...
Kind regards,
Bregt

Prometheus and Alertmanager - route based on env label

I'm trying to configure alertmanager so that it sends alerts to the right channels, based on value of a specific label. I have 3 slack channels - dev/staging/prod and I want the alerts coming from instances that have "env" label set to dev to be sent to the dev slack channel. Staging and prod would obviously work in the same manner. Here is part of my config:
global:
resolve_timeout: 1m
slack_api_url: 'https://slack-url'
route:
group_by: [...]
receiver: 'default'
routes:
- match:
env: 'prod'
receiver: 'slack-notifications-prod'
- match:
env: 'staging'
receiver: 'slack-notifications-staging'
- match:
env: 'dev'
receiver: 'slack-notifications-dev'
receivers:
- name: 'default'
- name: 'slack-notifications-prod'
...
- name: 'slack-notifications-staging'
...
- name: 'slack-notifications-dev'
...
The slack-notifications receivers are all the same and they only differ in one thing, which is the appropriate channel name.
Current behaviour: All alerts are sent to the prod slack channel
Expected behaviour: Alerts from "dev" env are sent to dev channel, "staging" to staging channel, and "prod" to prod channel.
Alertmanager sees these labels just fine (judging from the info from alertmanager webUI).
Turns out my config was fine and I was using a webhook URL which was tied only to one slack channel, I wasn't aware of that.
You have to add continue: true attribute on the first match:
global:
resolve_timeout: 1m
slack_api_url: 'https://slack-url'
route:
group_by: [...]
receiver: 'default'
routes:
- match:
env: 'prod'
receiver: 'slack-notifications-prod'
continue: true
- match:
env: 'staging'
receiver: 'slack-notifications-staging'
- match:
env: 'dev'
receiver: 'slack-notifications-dev'
receivers:
- name: 'default'
- name: 'slack-notifications-prod'
...
- name: 'slack-notifications-staging'
...
- name: 'slack-notifications-dev'
...
The AlertManager will evaluate children routes until there are no routes left or no routes for a given level are matching the current alert.
In that case, the AlertManager will take the configuration of the current node evaluated.
The continue attribute is a value used to define if you want to evaluate route siblings (belonging to the same level) if a route on the same level was already matching.
https://devconnected.com/alertmanager-and-prometheus-complete-setup-on-linux/

How to access AWS SAM Mapping in swagger.yaml / openapi.yaml files

I have declared a mapping named StageMap in my sam.yaml file:
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
ProjectName:
Type: String
SubProjectName:
Type: String
Stage:
Type: String
AllowedValues:
- dev
- test
- preprod
- prod
...
Mappings:
StageMap:
dev:
AuthorizerArn: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:auth-bk-main-dev-AuthorizerFunction-1RR2YJ5STBUB6/invocations
test:
AuthorizerArn: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:auth-bk-main-test-AuthorizerFunction-UQ1EQ2SP5W6G/invocations
preprod:
AuthorizerArn: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:auth-bk-main-preprod-AuthorizerFunction-UQ1W6EQ2SP5G/invocations
prod:
AuthorizerArn: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:auth-bk-main-prod-AuthorizerFunction-5STBUB61RR2YJ/invocations
I would like to use this mapping in my swagger.yaml I have tried the following:
...
x-amazon-apigateway-authorizer:
type: request
authorizerUri:
Fn::FindInMap:
- 'StageMap'
- Ref: 'Stage'
- 'AuthorizerArn
I also tried this solution but I got an error Every Mappings attribute must be a String or a List.
Can you please let me know how to access one of the values in the mapping in the swagger.yaml? Thanks!
I found the following in the AWS SAM docs:
You cannot include parameters, pseudo parameters, or intrinsic functions in the Mappings section.
So I changed:
AuthorizerArn: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:auth-bk-main-dev-AuthorizerFunction-1RR2YJ5STBUB6/invocations
For:
AuthorizerFunctionName: auth-bk-main-dev-AuthorizerFunction-1RR2YJ5STBUB6
And in the swagger.yaml I used the following:
x-amazon-apigateway-authorizer:
type: request
authorizerUri:
Fn::Sub:
- arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${AuthorizerFunctionName}/invocations
- AuthorizerFunctionName:
Fn::FindInMap:
- 'StageMap'
- Ref: 'Stage'
- 'AuthorizerFunctionName'

Prometheus alertmanager send notifications to multiple slack channel

We have two different teams working on different applications.I would like send alert notifications to different slack channels via using same alerts expressions. I found some examples but not understand what is the main reason to use receiver: 'default' when try to add new route? What is the role of this and what if it affects if ı change this?
Meanwhile will be appreciate if you can help how should I send the notifations to multiple slack channels.. New one is what I tried.
Current alertmanager.yml
receivers:
- name: 'team-1'
slack_configs:
- api_url: 'https://hooks.slack.com/services/1'
channel: '#hub-alerts'
route:
group_wait: 10s
group_interval: 5m
receiver: 'team-1'
repeat_interval: 1h
group_by: [datacenter]
New alertmanager.yml
alertmanager.yml:
receivers:
- name: 'team-1'
slack_configs:
- api_url: 'https://hooks.slack.com/services/1'
channel: '#channel-1'
send_resolved: true
- name: 'team-2'
slack_configs:
- api_url: 'https://hooks.slack.com/services/2'
channel: '#channel-2'
send_resolved: true
route:
group_wait: 10s
group_interval: 5m
repeat_interval: 1h
group_by: [datacenter]
receiver: 'default'
routes:
- receiver: 'team-1'
- receiver: 'team-2'
You need to set the continue property on your route to true. By default it is false.
The default behaviour of AlertManager is to traverse your routes for a match and exit at the first node it finds a match at.
What you want to do is fire an alert at the match and continue to search for other matches and fire those too.
Relevant documentation section: https://prometheus.io/docs/alerting/latest/configuration/#route
An example using this:
https://awesome-prometheus-alerts.grep.to/alertmanager.html
In-lined the example above in case it ever breaks.
# alertmanager.yml
route:
# When a new group of alerts is created by an incoming alert, wait at
# least 'group_wait' to send the initial notification.
# This way ensures that you get multiple alerts for the same group that start
# firing shortly after another are batched together on the first
# notification.
group_wait: 10s
# When the first notification was sent, wait 'group_interval' to send a batch
# of new alerts that started firing for that group.
group_interval: 5m
# If an alert has successfully been sent, wait 'repeat_interval' to
# resend them.
repeat_interval: 30m
# A default receiver
receiver: "slack"
# All the above attributes are inherited by all child routes and can
# overwritten on each.
routes:
- receiver: "slack"
group_wait: 10s
match_re:
severity: critical|warning
continue: true
- receiver: "pager"
group_wait: 10s
match_re:
severity: critical
continue: true
receivers:
- name: "slack"
slack_configs:
- api_url: 'https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/xxxxxxxxxxxxxxxxxxxxxxxxxxx'
send_resolved: true
channel: 'monitoring'
text: "{{ range .Alerts }}<!channel> {{ .Annotations.summary }}\n{{ .Annotations.description }}\n{{ end }}"
- name: "pager"
webhook_config:
- url: http://a.b.c.d:8080/send/sms
send_resolved: true
I have alertmanagerconfig with below configuration and now I need to point info alerts to a null receiver, can I have multiple receiver and receivers?
kind: AlertmanagerConfig
metadata:
name: Prometheus-alertmanager-config
namespace: Prometheus
spec:
route:
receiver: alert-email-pagerduty-config
groupBy: ['alertname', 'priority','severity']
groupWait: 30s
groupInterval: 5m
repeatInterval: 15m
continue: true
receivers:
- name: alert-email-pagerduty-config
emailConfigs:
- to: {{.to_email}}
sendResolved: true
from: {{.from_email}}
smarthost: {{.smarthost}}
authUsername: {{.mail_username}}
authPassword:
name: 'alert-smtp-password'
key: 'password'
requireTLS: true
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: alert-smtp-password
namespace: prometheus
stringData:
password: {{.mail_password}}

serverless framework with aws import function returns 404

I have two serverless app which are sharing the same custom authorizer. Suddenly the import function in the second serverless.yml file stopped working.
The app is based on https://github.com/medwig/serverless-shared-authorizer
gateway.serverless
service: authorizer-stack
provider:
name: aws
runtime: nodejs12.x
region: ap-south-1
profile: xxx-dev
functions:
authorizer:
handler: handler.auth
test:
handler: handler.privateEndpoint
events:
- http:
path: /api/test
method: get
authorizer:
type: CUSTOM
authorizerId:
Ref: Authorizer
test2:
handler: handler.publicEndpoint
events:
- http:
path: /api/test/public
method: get
resources:
Resources:
AuthorizerPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Fn::GetAtt: AuthorizerLambdaFunction.Arn
Action: lambda:InvokeFunction
Principal:
Fn::Join: ["",["apigateway.", { Ref: "AWS::URLSuffix"}]]
Authorizer:
DependsOn:
- ApiGatewayRestApi
Type: AWS::ApiGateway::Authorizer
Properties:
Name: ${self:provider.stage}-Authorizer
RestApiId: { "Ref" : "ApiGatewayRestApi" }
Type: TOKEN
IdentitySource: method.request.header.Authorization
AuthorizerResultTtlInSeconds: 300
AuthorizerUri:
Fn::Join:
- ''
-
- 'arn:aws:apigateway:'
- Ref: "AWS::Region"
- ':lambda:path/2015-03-31/functions/'
- Fn::GetAtt: "AuthorizerLambdaFunction.Arn"
- "/invocations"
Outputs:
AuthorizerId:
Value:
Ref: Authorizer
Export:
Name: authorizerId
apiGatewayRestApiId:
Value:
Ref: ApiGatewayRestApi
Export:
Name: restApiId
apiGatewayRestApiRootResourceId:
Value:
Fn::GetAtt:
- ApiGatewayRestApi
- RootResourceId
Export:
Name: rootResourceId
products serverless
service: products-list
provider:
name: aws
runtime: nodejs12.x
region: ap-south-1
profile: xxx-dev
apiGateway:
restApiId:
Fn::ImportValue: authorizer-stack-dev-restApiId
restApiRootResourceId:
Fn::ImportValue: authorizer-stack-dev-rootResourceId
functions:
get-products:
handler: handler.getProducts
events:
- http:
path: /api/products
method: get
authorizer:
type: CUSTOM
authorizerId:
Fn::ImportValue: authorizer-stack-dev-authorizerId
I am getting the following errors at random
An error occurred: products-list-dev - No export named authorizer-stack-dev-restApiId found.
An error occurred: products-list-dev - No export named authorizer-stack-dev-rootResourceId found.
An error occurred: products-list-dev - No export named authorizer-stack-dev-authorizerId found.
What am I missing here?
serverless -v
Framework Core: 1.74.1
Plugin: 3.6.15
SDK: 2.3.1
Components: 2.31.10
From the shared authorizers I have configured in the past it is not necessary to go to the effort you have undergone. The documentation on the Serverless Framework site has a much simpler setup to achieve a shared authoriser and I will always go with the simplest solution possible: https://www.serverless.com/framework/docs/providers/aws/events/apigateway#share-authorizer

Resources