Note: This repository has been archived.
This is a set of middlewares created for gobis usable on your on project containing gobis.
Note: They are loaded by default on gobis-server
List:
- basic2token: Give the ability to connect a user over basic auth, retrieve a token from an OAuth2 server with user information and forward the request with this token.
- basic auth
- casbin: An authorization library that supports access control models like ACL, RBAC, ABAC
- cef trace: Produce access log in CEF format for siem.
- cf check permission: Check if user has access to a service instance on a cloud foundry platform.
- circuit breaker
- conn limit
- cors
- infopage: Add an endpoint on upstream to see information like headers set by gobis and user informations set by middlewares (Useful for frontend)
- JWT
- oauth2
- oauth2request
- ldap
- secure: An HTTP middleware for Go that facilitates some quick security wins
- rate limit
- trace
Pro tip:
You can set multiple middleware params programmatically by using a dummy structure containing each config you want to set, example:
package main
import (
"github.com/orange-cloudfoundry/gobis"
"github.com/orange-cloudfoundry/gobis-middlewares/cors"
"github.com/orange-cloudfoundry/gobis-middlewares/trace"
)
func main() {
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: struct {
trace.TraceConfig
cors.CorsConfig
}{
TraceConfig: trace.TraceConfig{
Trace: &trace.TraceOptions{
Enabled: true,
},
},
CorsConfig: cors.CorsConfig{
Cors: &cors.CorsOptions{
Enabled: true,
},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(trace.NewTrace(), cors.NewCors()))
}
Give the ability to connect a user over basic auth, retrieve a token from an OAuth2 server with user information and forward the request with this token.
This was made to transparently convert a basic auth authentication to an OAuth2 one.
See godoc for Basic2TokenOptions to know more about parameters.
Note:
- Your oauth2 server must have the
password
grant type such as UAA or Gitlab in oauth2 provider
import "github.com/orange-cloudfoundry/gobis-middlewares/basic2token"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: basic2token.Basic2TokenConfig{
Ldap: &basic2token.Basic2TokenOptions{
Enable: true,
AccessTokenUri: "https://my.uaa.local/oauth/token",
ClientId: "cf",
ClientSecret: "",
ParamsAsJson: false,
UseRouteTransport: true,
InsecureSkipVerify: true,
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(basic2token.NewBasic2Token()))
// create your server
middleware_params:
basic2token:
enabled: true
access_token_uri: https://my.uaa.local/oauth/token
client_id: cf
client_secret: ~
params_as_json: false
use_route_transport: false
insecure_skip_verify: true
- If key
scope
is found in the response of the oauth2 server, theses scopes will be loaded as groups and others middlewares will be able to find groups for the current user by using context groups - Logged user is accessible by other middleware through context username
Add basic auth to upstream
See godoc for BasicAuthOption to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/basicauth"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: basicauth.BasicAuthConfig{
BasicAuth: &basicauth.BasicAuthOptions{
{
User: "user",
Password: "$2y$12$AHKssZrkmcG2pmom.rvy2OMsV8HpMHHcRIEY158LgZIkrA0BFvFQq", // equal password
Crypted: true, // hashed by bcrypt, you can use https://github.com/gibsjose/bcrypt-hash command to crypt a password
},
{
User: "user2",
Password: "mypassword",
Groups: []string{"admin"}
},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(basicauth.NewBasicAuth()))
// create your server
middleware_params:
basic_auth:
- user: user
password: $2y$12$AHKssZrkmcG2pmom.rvy2OMsV8HpMHHcRIEY158LgZIkrA0BFvFQq # equal password
crypted: true # hashed by bcrypt, you can use https://github.com/gibsjose/bcrypt-hash command to crypt a password
- user: user2
password: mypassword # equal password
groups: [admin]
- By setting groups it will allow others middleware to find groups for the current user by using context groups
- If you use bcrypt more the cost will be higher more it will take time to test a password against it and will increase response time
casbin is an authorization library that supports access control models like ACL, RBAC, ABAC.
This middleware allow you to add access control over your apo
See godoc for CasbinOption to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/casbin"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: casbin.CasbinConfig{
CircuitBreaker: &casbin.CasbinOption{
Enabled: true,
Policies: []casbin.CasbinPolicy{
Type: "p",
Sub: "usernameOrGroupName",
Obj: "/mysubpath/*"
Act: "*",
},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(casbin.NewCasbin()))
// create your server
middleware_params:
casbin:
enabled: true
policies:
- {type: p, sub: usernameOrGroupName, obj: /mysubpath/*, act: *}
- It will load as role policies all groups found by using context groups
this allow you, if you use ldap middleware, to pass a group name found as a
sub
(e.g.:sub: myUserGroupName
) - It will also load all policies found in context key
casbin.PolicyContextKey
this allow other middleware to add their own policies
Produce access log in CEF format for siem.
See godoc for CefTraceOptions to know more about parameters.
Trace will take the form:
CEF:0|device_vendor|device_product|device_version|my-sig|GET /path/request|0|rt=<unix timestamp> request=/path/request requestMethod=GET httpStatusCode=200 src=10.0.0.1 suser=user-gobis sgroups=group,gobis xForwardedFor=10.0.0.2
import "github.com/orange-cloudfoundry/gobis-middlewares/ceftrace"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: cf_checkpermission.CfCheckPermissionConfig{
CefTrace: &ceftrace.CefTraceOptions{
Enabled: true,
DeviceVendor: "device_vendor",
DeviceProduct: "device_product",
DeviceVersion: "device_version",
KeySignatureID: "my-sig",
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(ceftrace.NewCefTrace()))
// create your server
middleware_params:
cef_trace:
enabled: true
device_vendor: device_vendor
device_product: device_product
device_version: device_version
key_signature_id: my-sig
Check if user has access to a service instance on a cloud foundry platform.
See godoc for CorsOptions to know more about parameters.
You must use this middleware with oauth2 middleware, client must have scope cloud_controller_service_permissions.read
import "github.com/orange-cloudfoundry/gobis-middlewares/cf_checkpermission"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: cf_checkpermission.CfCheckPermissionConfig{
Cors: &cf_checkpermission.CfCheckPermissionOptions{
Enabled: true,
ApiEndpoint: "https://api.my.cloudfoundry",
InstanceGUID: "service-instance-guid",
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(cors.NewCors()))
// create your server
middleware_params:
cf_checkpermission:
enabled: true
api_endpoint: https://api.my.cloudfoundry
instance_guid: service-instance-guid
only_manager: false
Hystrix-style circuit breaker
See godoc for CircuitBreakerOption to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/cbreaker"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: cbreaker.CircuitBreakerConfig{
CircuitBreaker: &cbreaker.CircuitBreakerOptions{
Enabled: true,
Expression: "NetworkErrorRatio() < 0.5",
FallbackUrl: "http://my.fallback.com",
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(cbreaker.NewCircuitBreaker()))
// create your server
middleware_params:
circuit_breaker:
enabled: true
expression: NetworkErrorRatio() < 0.5
fallback_url: http://my.fallback.com
Limit number of simultaneous connection
See godoc for ConnLimitOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/connlimit"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: connlimit.ConnLimitConfig{
ConnLimit: &connlimit.ConnLimitOptions{
Enabled: true,
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(connlimit.NewConnLimit()))
// create your server
middleware_params:
conn_limit:
enabled: true
Add cors headers to response
See godoc for CorsOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/cors"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: cors.CorsConfig{
Cors: &cors.CorsOptions{
Enabled: true,
AllowedOrigins: []string{"http://localhost"},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(cors.NewCors()))
// create your server
middleware_params:
cors:
enabled: true
max_age: 12
allowed_origins:
- http://localhost
Add an endpoint on upstream to see information like headers set by gobis and user information set by middlewares (Useful for frontend)
See godoc for CorsOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/infopage"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: infopage.InfoPageConfig{
Cors: &infopage.InfoPageOptions{
Enabled: true,
Path: "/user_info",
ShowAuthorizationHeader: true,
AuthorizationKeyName: "token",
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(infopage.NewInfoPage()))
// create your server
middleware_params:
info_page:
enabled: true
path: /user_info
show_authorization_header: true
authorization_key_name: token
Example of json when going to the endpoint /user_info
when using infopage with oauth2 middleware:
{
"forward": "true",
"token": "bearer atokencontent",
"username": "ausername",
"groups": ["group1", "group2"]
}
Verify a JWT token with its secret/pubkey and can give scopes as groups through context groups to use it in others middlewares
See godoc for JwtOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/jwt"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: jwt.JwtConfig{
Ldap: &jwt.JwtOptions{
Enabled: true,
Alg: "RS256", // this is mandatory due to security issue: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries
Secret: "hmac secret or ECDSA/RSA public key",
Issuer: "https://issuer.which.sign.token.com",
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(jwt.NewJwt()))
// create your server
middleware_params:
jwt:
enabled: true
alg: RS256
secret: hmac secret or ECDSA/RSA public key
issuer: https://issuer.which.sign.token.com
- If key
scope.*
is found in the jwt token, thoses scopes will be loaded as groups and others middlewares will be able to find groups for the current user by using context groups
Add basic authentiation based on ldap to upstream
See godoc for LdapOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/ldap"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: ldap.LdapConfig{
Ldap: &ldap.LdapOptions{
Enabled: true,
BindDn: "uid=readonly,dc=com",
BindPassword: "password",
Address: "ldap.example.com:636",
InsecureSkipVerify: true,
UseSsl: true,
SearchBaseDns: "dc=example,dc=com",
SearchFilter: "(objectClass=organizationalPerson)&(uid=%s)",
GroupSearchBaseDns: "ou=Group,dc=example,dc=com",
GroupSearchFilter: "(&(objectClass=posixGroup)(memberUid=%s))",
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(ldap.NewLdap()))
// create your server
middleware_params:
ldap:
enabled: true
bind_dn: uid=readonly,dc=com
bind_password: password
address: ldap.example.com:636
insecure_skip_verify: true
use_ssl: true
search_base_dns: dc=example,dc=com
search_filter: (objectClass=organizationalPerson)&(uid=%s)
group_search_base_dns: ou=Group,dc=example,dc=com
group_search_filter: (&(objectClass=posixGroup)(memberUid=%s))
If GroupSearchBaseDns
and GroupSearchFilter
params are set the middleware will pass in context
the list of group accessible by other middlewares by using context groups
Add oauth2 authentication underlying upstream
See godoc for Oauth2Options to know more about parameters.
Note: If a JWT token is provided by your oauth2 provider you should always use JWT middleware to verify it.
import "github.com/orange-cloudfoundry/gobis-middlewares/oauth2"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: oauth2.Oauth2Config{
Ldap: &oauth2.Oauth2Options{
Enabled: true,
ClientId: "myclientid",
ClientSecret: "myclientsecret",
AuthorizationUri: "http://github.com/login/oauth/authorize",
AccessTokenUri: "http://github.com/login/oauth/access_token",
UserInfoUri: "https://api.github.com/user",
UseRouteTransport: true,
InsecureSkipVerify: false,
LoginPath: "/login",
LogoutPath: "/logout",
AuthKey: "my-super-strong-auth-key",
Scopes: []string{},
PassToken: false,
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(oauth2.NewOauth2()))
// create your server
middleware_params:
oauth2:
enabled: true
client_id: myclientid
client_secret: myclientsecret
authorization_uri: http://github.com/login/oauth/authorize
access_token_uri: https://github.com/login/oauth/access_token
user_info_uri: https://api.github.com/user
auth_key: my-super-strong-auth-key
login_path: /login
logout_path: /logout
use_route_transport: true
insecure_skip_verify: false
pass_token: false
scopes: []
- If user info uri is set username will retrieve from it and be passed through context username to use it in others middlewares
- Scopes will be loaded as groups and others middlewares will be able to find groups for the current user by using context groups
- Other middlewares can access to http client with oauth2 context by calling
oauth2.Oauth2Client(req)
where req is*http.Request
variable
Retrieve a token with oauth2 client credentials and pass it to upstream
See godoc for Oauth2RequestOptions to know more about parameters.
THIS SHOULD BE USED CAREFULLY AS IT CAN BE A SECURITY ISSUE
package main
import "github.com/orange-cloudfoundry/gobis-middlewares/oauth2request"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: oauth2request.Oauth2RequestConfig{
Ldap: &oauth2request.Oauth2RequestOptions{
Enabled: true,
ClientId: "myclientid",
ClientSecret: "myclientsecret",
AccessTokenUri: "http://github.com/login/oauth/access_token",
UseRouteTransport: true,
InsecureSkipVerify: false,
Scopes: []string{},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(oauth2request.NewOauth2Request()))
// create your server
middleware_params:
oauth2:
enabled: true
client_id: myclientid
client_secret: myclientsecret
access_token_uri: https://github.com/login/oauth/access_token
use_route_transport: true
insecure_skip_verify: false
scopes: []
Limit number of request in period of time
See godoc for RateLimitOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/ratelimit"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: ratelimit.RateLimitConfig{
RateLimit: &ratelimit.RateLimitOptions{
Enabled: true,
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(ratelimit.NewRateLimit()))
// create your server
middleware_params:
rate_limit:
enabled: true
Secure is an HTTP middleware for Go that facilitates some quick security wins.
See godoc for SecureOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/secure"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: secure.SecureConfig{
RateLimit: &secure.SecureOptions{
Enabled: true,
AllowedHosts: []string{"ssl.example.com"},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(secure.NewSecure()))
// create your server
middleware_params:
secure:
enabled: true
allowed_hosts: ["ssl.example.com"]
Structured request and response logger
See godoc for TraceOptions to know more about parameters.
import "github.com/orange-cloudfoundry/gobis-middlewares/trace"
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: trace.TraceConfig{
Trace: &trace.TraceOptions{
Enabled: true,
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(trace.NewTrace()))
// create your server
middleware_params:
trace:
enabled: true