Couper is a lightweight API gateway designed to support developers in building and operating API-driven Web projects

Overview

Couper

Go Go Report Docker

Couper

Couper is a lightweight API gateway designed to support developers in building and operating API-driven Web projects.

Getting started

Features

Couper …

  • is a proxy component connecting clients with (micro) services
  • adds access control and observability to the project
  • needs no special development skills
  • is easy to configure & integrate
  • runs on Linux, Mac OS X, Windows, Docker and Kubernetes.

Key features are:

  • Easy Configuration & Deployment
  • HTTP Request Routing / Forwarding
  • Custom Requests and Responses
  • Request / Response Manipulation
  • Centralized Access-Control Layer:
    • Basic-Auth
    • JWT Validation & Signing
    • Single Sign On with SAML2
    • OAuth2 Client Credentials
  • Configurable Service Connectivity
  • Upstream Validation & CORS
  • SPA & Web Serving
  • Error Handling
  • Observability

The full list of features of Couper 1.x is here or at couper.io.

Developers

Developers requiring Go to start with make build. Couper requires a configuration file. You can start with a simple one and use:

./couper run -f public/couper.hcl

Contributing

Thanks for your interest in contributing.

If you have any questions or feedback you are welcome to start a discussion.

If you have an issue please open an issue.

Issues
  • check and log ulimits on startup

    check and log ulimits on startup

    We would like to check the current ulimit for our Couper process. Especially in docker environments this information could be very helpful.

    Check and log the current and max system settings. If the number is below a constant threshold, lets start with 4096, log as warn level.

    Implementation could take place within the run command.

    hacktoberfest 
    opened by malud 9
  • OpenAPI upstream request/response validation

    OpenAPI upstream request/response validation

    We want to prevent invalid upstream request and responses which does not match the requirements from a given openAPI yaml file.

    • [x] implementation
    • [x] documentation
    enhancement spec theme/config 
    opened by johakoch 8
  • Implement SAML2 assertion access control

    Implement SAML2 assertion access control

    An access control to be used in a SAML2 assertion consumer service endpoint.

    https://cheatsheetseries.owasp.org/cheatsheets/SAML_Security_Cheat_Sheet.html mentions some security issues and how to address them.

    https://tools.ietf.org/html/rfc7522#section-3 (which describes a similar case) has some requirements for assertion format and processing requirements.

    The following is a mix of requirements:

    • check RelayState param (= RelayState from AuthN request query param)
    • always perform schema validation on the XML document prior to using it for any security-­related purposes.
    • validate SAML2 response:
      • valid signature (from IdP metadata file (and samlp:Response/ds:Signature))
      • samlp:Response/@Destination (= ACS endpoint URL of SP)
      • samlp:Response/@InResponseTo (= samlp:AuthnRequest/@ID of the AuthN request)
      • samlp:Response/saml:Issuer (= entity_id of IdP, from IdP metadata file)
      • check samlp:Response/samlp:Status/samlp:StatusCode/@Value
    • validate incoming SAML2 assertion:
      • valid signature (from IdP metadata file (and saml:Assertion/ds:Signature))
      • saml:Assertion/saml:Issuer (= entity_id of IdP, from IdP metadata file)
      • saml:Assertion/saml:Conditions/saml:AudienceRestriction/saml:Audience (= entity_id of SP, from Couper config)
      • has saml:Assertion/saml:Subject/saml:Subject
      • saml:Assertion/saml:Conditions/@NotOnOrAfter or saml:Assertion/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData/@NotOnOrAfter
        • saml:Assertion/saml:Conditions/@NotOnOrAfter: if time passed, reject Assertion
        • saml:Assertion/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData/@NotOnOrAfter: if time passed, reject SubjectConfirmation
      • saml:Assertion/saml:Subject/saml:SubjectConfirmation/@Method (= 'urn:oasis:names:tc:SAML:2.0:cm:bearer')
      • saml:Assertion/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData/@Recipient (= ACS endpoint URL of SP)
      • saml:Assertion/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData/@InResponseTo (= samlp:AuthnRequest/@ID of the AuthN request)
      • check saml:Assertion/saml:AuthnStatement/saml:AuthnContext/saml:AuthnContextClassRef
      • if invalid: create HTML error response, because the request is a front-channel request
    • transform attributes about the authenticated user into claims, which may be used elsewhere in JWT creation
      saml2 "SAML_AC" {
        # the XML metadata about the identity provider
        idp_metadata_file = "idp-metadata.xml"
        # the entity id of the service provider (couper)
        entity_id = "my-couper-api"
    
        # single sign on service (idp)
        sso_binding = "HTTP-Redirect" # irrelevant for access control?
        # assertion consumer service (couper)
        acs_binding = "HTTP-Post"
        # alternative: binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    
        # whether to generate JSON claims
        generate_json_claims = true
        # which `saml:Attribute` elements are expected to possibly have multiple `saml:AttributeValue` element children
        array_attributes = ["memberOf"]
        
        # generates:
        #claims = {
        #  iss = "https://the-id-provider.com…" # saml:Assertion/saml:Issuer
        #  sub = "username" # saml:Assertion/saml:Subject/saml:NameID
        #  exp = 1612371650 # saml:Assertion/saml:Conditions/@NotOnOrAfter -> unixtime
        #  nbf = 1612300000 # saml:Assertion/saml:Conditions/@NotBefore -> unixtime
        #  iat = 1612300010 # saml:Assertion/@IssueInstant -> unixtime
        #  aud = "my-couper-api" # saml:Assertion/saml:Conditions/saml:AudienceRestriction/saml:Audience
        #  # loop saml:Assertion/saml:AttributeStatement/saml:Attribute -> @Name = ./saml:AttributeValue
        #  displayName = "Doe, John (External)"
        #  objectSid = "S-1-5-21-123456789-0123456789-123456789-000001"
        #  mail = "[email protected]"
        #  # Attribute with multiple AttributeValue's become arrays?
        #  memberOf = [
        #    "admin",
        #    "users",
        #    "CN=Special AD Group,OU=foo,DC=example,DC=com"
        #  ]
        #}
      }
    
    opened by johakoch 7
  • Upgrade to Go 1.17

    Upgrade to Go 1.17

    Upgrade to go 1.17

    • update go.mod
    • update Dockerfile
    • update GitHub actions
    • fix new go vet errors

    resolves #330


    Reviewer checklist
    • Read PR description: a summary about the changes is required
    • Changelog updated
    • Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage
    • Pulled branch, manually tested
    • Verified requirements are met
    • Reviewed the code
    • Reviewed the related tests
    opened by develerik 4
  • Explicitly pass non-json upstream response body `backend_responses.<label>.body`

    Explicitly pass non-json upstream response body `backend_responses.

    When I define an upstream request with a label (other than default), I have to define a response{}, too. Because otherwise Couper wouldn't know what to pass downstream.

    It is straight-forward to define response status and headers. But currently I cannot simply copy the response body:

    server "pass" {
      endpoint "/teapot" {
        request "st" {
          url = "https://httpbin.org/status/418"
        }
        response {
          status = backend_responses.st.status
          headers = backend_responses.st.headers
          body = backend_responses.st.body
        }
      }
    }
    

    … because backend_responses.<label>.body doesn't exist :)

    We should provide the de-chunked, de-compressed bytes of the response body in that property. E.g. to allow for useless string expressions like

     "Body was: ${backend_responses.st.body}"
    

    The string must also be binary-safe to pass arbitrary content, e.g. pass a PDF generated by an upstream service. (And a binary-string containing a null byte shouldn't truncate the value :))

    At first, it's not about optimizing this kind of operation. We can buffer the download, pull the bytes it through the expression evaluation and then compress them on the way to the client.

    enhancement 
    opened by filex 4
  • Log parent-field should wrap all logs

    Log parent-field should wrap all logs

    Couper offers two settings to wrap JSON log lines into a parent field. This is useful to avoid field clashes in the log db (e.g. ElasticSearch / ELK). I recently had that situation in a project running in Kubernetes where logs were supposed to ship via Logstash to a ES.

    I have used these env vars:

    COUPER_ACCESS_LOG_PARENT_FIELD=couper
    COUPER_BACKEND_LOG_PARENT_FIELD=couper
    

    As one would expect, this works for Couper's access log and backend log.

    However, there are more log "types" that Couper uses. For example those with type":"couper_daemon. Those lines are used for startup messages and some generic errors that don't belong elsewhere.

    I propose that we introduce a single setting that configures a wrapper object for all couper logs:

    COUPER_LOG_PARENT_FIELD=couper
    

    This way I

    • don't loose any less obvious loglines
    • have to write less env var settings
    bug 
    opened by filex 3
  • config: add coalesce() function

    config: add coalesce() function

    Currently, hcl does not support a null coalesce operator for default values. Until then, we can use the coalesce() function from cty's stdlib.

    This would allow us to easily define default values:

    user = coalesce(env.USER, "default")
    
    opened by filex 3
  • Support for nested struct environment mapping

    Support for nested struct environment mapping

    Currently we are able to map environment variables to configuration structs via tag.

    An example:

    type Config struct {
      DefaultPort int `env:"default_port"`
    }
    

    This gets internally prefixed with COUPER_ and uppercased. The value of COUPER_DEFAULT_PORT will be assigned to Config.DefaultPort.

    The following example is not possible at this moment but should:

    type Config struct {
      DefaultPort int `env:"default_port"`
      Timings Timings
    }
    
    Type Timings struct {
      Timeout time.Duration `env:"timeout"`
    }
    

    Env COUPER_TIMEOUT must be assigned to Config.Timings.Timeout.

    Related files are config/env/env.go and runtime/http.go makes use of it.

    enhancement good first issue theme/config 
    opened by malud 3
  • Multiple error handler labels

    Multiple error handler labels

    config.ErrorHandler with only one Kind; configload.kindContent with only one kind; avoid double iteration


    Reviewer checklist
    • Read PR description: a summary about the changes is required
    • Changelog updated
    • Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage
    • Pulled branch, manually tested
    • Verified requirements are met
    • Reviewed the code
    • Reviewed the related tests
    opened by johakoch 2
  • OAuth2

    OAuth2 "password flow"

    OAuth2 password flow as a hidden feature

            backend {
              oauth2 {
                grant_type = "password"
                token_endpoint = "http://localhost:8081/token"
                client_id = env.OAUTH_CLIENT_ID
                client_secret = env.OAUTH_CLIENT_SECRET
                username = env.OAUTH_USERNAME
                password = env.OAUTH_PASSWORD
              }
            }
    

    WARNING: This is no proper implementation of the OAuth2 password flow, as the received access token is stored for the client (like with the client credentials flow) and not per user. However, this is a solution for the very limited use case where the client requests a token on behalf of exactly one (system) user without any user interaction.


    Reviewer checklist
    • Read PR description: a summary about the changes is required
    • Changelog updated
    • Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage
    • Pulled branch, manually tested
    • Verified requirements are met
    • Reviewed the code
    • Reviewed the related tests
    opened by johakoch 2
  • Multi-file-config

    Multi-file-config

    reads and merges configuration files from a given directory


    Reviewer checklist
    • Read PR description: a summary about the changes is required
    • Changelog updated
    • Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage
    • Pulled branch, manually tested
    • Verified requirements are met
    • Reviewed the code
    • Reviewed the related tests
    opened by alex-schneider 2
  • Exp status vs openapi

    Exp status vs openapi

    Fix the order of errors. Fix HTTP status code for unexpected_status error.


    Reviewer checklist
    • Read PR description: a summary about the changes is required
    • Changelog updated
    • Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage
    • Pulled branch, manually tested
    • Verified requirements are met
    • Reviewed the code
    • Reviewed the related tests
    opened by alex-schneider 0
  • Uniformly code handling of errors

    Uniformly code handling of errors

    Describe your changes!


    Reviewer checklist
    • Read PR description: a summary about the changes is required
    • Changelog updated
    • Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage
    • Pulled branch, manually tested
    • Verified requirements are met
    • Reviewed the code
    • Reviewed the related tests
    opened by alex-schneider 0
  • OpenAPI: resolve servers: relative url with backend origin

    OpenAPI: resolve servers: relative url with backend origin

    The OpenAPI file may have defined servers with urls which could be absolute or relative. This leads to invalid requests for relative ones. We must add the current backend origin host to the relative OpenAPI server url.

    Implementation: Since the backend origin gets evaluated during runtime the openAPI configuration must move to a runtime factory.

    bug 
    opened by malud 0
  • Security check for Upstream Request Validation

    Security check for Upstream Request Validation

    If the OpenAPI3 description of an upstream API mentions security requirements (security) for routes, Couper should perform security checks when validating requests to this upstream API (according to the referenced security scheme objects in components.securitySchemes):

    • type: http
      • scheme: basic: header "Authorization: Basic ..." set?
      • scheme: bearer: header "Authorization: Bearer ..." set?
    • type: apiKey
      • in: query; name: <query_param>: query parameter <query_param> set?
      • in: header; name: <header_name>: header <header_name> set?
      • in: cookie; name: <cookie_name>: cookie <cookie_name> set?
    • type: oauth2/openIdConnect: header "Authorization: Bearer ..." set?

    If security references several security scheme objects, the requirements must be ANDed or ORed accordingly.

    This additional check should be configurable (default is ~~on~~true~~; performed only if upstream request validation is on~~).

    enhancement spec theme/access_control theme/config 
    opened by johakoch 1
  • Send WWW-Authenticate response header and appropriate status code for unauthorized bearer requests

    Send WWW-Authenticate response header and appropriate status code for unauthorized bearer requests

    The OAuth 2.0 Authorization Framework: Bearer Token Usage

    (This is the RFC defining Bearer Authorization.)

    Section "3. The WWW-Authenticate Response Header Field":

    If the protected resource request does not include authentication credentials or does not contain an access token that enables access to the protected resource, the resource server MUST include the HTTP "WWW-Authenticate" response header field; it MAY include it in response to other conditions as well.

    If the protected resource request included an access token and failed authentication, the resource server SHOULD include the "error" attribute to provide the client with the reason why the access request was declined. The parameter value is described in Section 3.1. In addition, the resource server MAY include the "error_description" attribute to provide developers a human-readable explanation that is not meant to be displayed to end-users. It also MAY include the "error_uri" attribute with an absolute URI identifying a human-readable web page explaining the error. The "error", "error_description", and "error_uri" attributes MUST NOT appear more than once.

    Example:

         HTTP/1.1 401 Unauthorized
         WWW-Authenticate: Bearer realm="example",
                           error="invalid_token",
                           error_description="The access token expired"
    

    Section "3.1. Error Codes":

    invalid_token The access token provided is expired, revoked, malformed, or invalid for other reasons. The resource SHOULD respond with the HTTP 401 (Unauthorized) status code. The client MAY request a new access token and retry the protected resource request.

    Currently, the status code for a rejected request (lacking authrorization or with an invalid token) is 403 (Forbidden), which SHOULD be used for insufficient privileges:

    insufficient_scope The request requires higher privileges than provided by the access token. The resource server SHOULD respond with the HTTP 403 (Forbidden) status code and MAY include the "scope" attribute with the scope necessary to access the protected resource.

    bug theme/access_control 
    opened by johakoch 4
Releases(v1.8.1)
lightweight, idiomatic and composable router for building Go HTTP services

chi is a lightweight, idiomatic and composable router for building Go HTTP services. It's especially good at helping you write large REST API services

go-chi 11.4k May 17, 2022
⚡ Rux is an simple and fast web framework. support middleware, compatible http.Handler interface. 简单且快速的 Go web 框架,支持中间件,兼容 http.Handler 接口

Rux Simple and fast web framework for build golang HTTP applications. NOTICE: v1.3.x is not fully compatible with v1.2.x version Fast route match, sup

Gookit 77 Apr 16, 2022
Golanger Web Framework is a lightweight framework for writing web applications in Go.

/* Copyright 2013 Golanger.com. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except

golanger 299 Mar 3, 2022
A Go framework for building JSON web services inspired by Dropwizard

Tiger Tonic A Go framework for building JSON web services inspired by Dropwizard. If HTML is your game, this will hurt a little. Like the Go language

Richard Crowley 1000 Apr 29, 2022
package for building REST-style Web Services using Go

go-restful package for building REST-style Web Services using Google Go Code examples using v3 REST asks developers to use HTTP methods explicitly and

Ernest Micklei 4.5k May 18, 2022
Bramble is a production-ready GraphQL federation gateway.

Bramble is a production-ready GraphQL federation gateway. It is built to be a simple, reliable and scalable way to aggregate GraphQL services together.

Movio 407 May 16, 2022
Simple and lightweight Go web framework inspired by koa

VOX A golang web framework for humans, inspired by Koa heavily. Getting started Installation Using the go get power: $ go get -u github.com/aisk/vox B

An Long 76 Mar 23, 2022
Dragon 🐲 🐲 🐲 is a lightweight high performance web framework with Go for the feature and comfortable develop.

Dragon project new link start dragon ab performance Dragon ?? ?? ?? is a lightweight high performance web framework with Go for the feature and comfor

azerothyang 13 Apr 6, 2022
skr: The lightweight and powerful web framework using the new way for Go.Another go the way.

skr Overview Introduction Documents Features Install Quickstart Releases Todo Pull Request Issues Thanks Introduction The lightweight and powerful web

go-the-way 1 Jan 11, 2022
henrylee2cn 1.6k May 17, 2022
Building basic API with go, gin and gorm

Project Description Terima kasih sudah berkunjung ke halaman repositori ini, repositori ini berisi basic RESTFUL API dengan menggunakan teknologi seba

dev-beard 1 Nov 20, 2021
hiboot is a high performance web and cli application framework with dependency injection support

Hiboot - web/cli application framework About Hiboot is a cloud native web and cli application framework written in Go. Hiboot is not trying to reinven

hidevops.io 169 May 10, 2022
A minimal framework to build web apps; with handler chaining, middleware support; and most of all standard library compliant HTTP handlers(i.e. http.HandlerFunc).

WebGo v4.1.3 WebGo is a minimalistic framework for Go to build web applications (server side) with zero 3rd party dependencies. Unlike full-fledged fr

Kamaleshwar 240 May 3, 2022
Lightweight web framework based on net/http.

Goweb Light weight web framework based on net/http. Includes routing middleware logging easy CORS (experimental) Goweb aims to rely only on the standa

Travis Harmon 32 May 9, 2022
Eudore is the core of a golang lightweight web framework.

Eudore eudore是一个golang轻量级web框架核心,可以轻松扩展成一个技术栈专用框架,具有完整框架设计体系。 反馈和交流请加群组:QQ群373278915。 Features 易扩展:主要设计目标、核心全部解耦,接口即为逻辑。 简单:对象语义明确,框架代码量少复杂度低,无依赖库。 易用

null 71 Apr 6, 2022
A lightweight RESTful web framework for Go

Goweb A lightweight RESTful web framework for Go. For examples and usage, please read the Goweb API Documentation Read our Articles Who uses Goweb? "U

Stretchr, Inc. 630 May 10, 2022
🐶 Next generation building tool for nothing

Oscar ?? Next generation building tool for nothing Motivation Imitation is the sincerest form of flattery. Oscar is yet another nonsense activity gene

dongdong 68 Dec 9, 2021
Best simple, lightweight, powerful and really fast Api with Golang (Fiber, REL, Dbmate) PostgreSqL Database and Clean Architecture

GOLANG FIBER API (CLEAN ARCHITECTURE) Best simple, lightweight, powerful and really fast Api with Golang (Fiber, REL, Dbmate) PostgreSqLDatabase using

Elias Champi 1 Apr 27, 2022