Fortificando APIs no Linux: Integração Profunda de Kong Gateway e Keycloak para Segurança DevOps

A segurança de APIs é uma fundação crítica em qualquer arquitetura de microsserviços moderna. Com o crescimento exponencial de APIs expondo funcionalidades de negócios, a gestão de autenticação, autorização e controle de acesso tornou-se uma preocupação central. A integração do Kong Gateway como um proxy reverso e gerenciador de APIs, juntamente com o Keycloak como uma solução de gerenciamento de Identidade e Acesso (IAM) de código aberto, oferece uma combinação poderosa para estabelecer uma camada de segurança robusta e escalável em ambientes linux. Esta abordagem, alinhada aos princípios DevOps, visa automação, repetibilidade e segurança inerente à infraestrutura.

Visão Arquitetural da Proteção de APIs

A configuração de segurança para APIs com Kong e Keycloak tipicamente envolve uma arquitetura onde o Kong atua como o ponto de entrada principal para todas as APIs. Ele intercepta as requisições, as valida, e então as encaminha para os serviços de backend (APIs) apropriados. O Keycloak, por sua vez, é o provedor de identidade (IdP), responsável por autenticar usuários e clientes, emitir tokens de acesso (OAuth 2.0/OpenID Connect) e gerenciar permissões. A integração se dá através do plugin OpenID Connect (OIDC) do Kong, que delega a autenticação e validação de tokens ao Keycloak. Essa delegação permite que os serviços de backend foquem na lógica de negócio, enquanto a segurança é centralizada no Kong.

Pré-requisitos do Ambiente Linux

Para prosseguir com a implementação, é essencial ter um ambiente Linux configurado com as ferramentas fundamentais. Recomenda-se uma distribuição baseada em Debian ou RHEL, com os seguintes componentes instalados:

  • Docker e Docker Compose: Para orquestração dos serviços Kong, Keycloak e PostgreSQL.
  • curl: Ferramenta de linha de comando para interagir com APIs.
  • jq: Processador JSON de linha de comando, útil para analisar respostas de APIs.
  • Git: Para clonar repositórios de configuração, se aplicável.

A instalação do Docker e Docker Compose pode ser realizada conforme a documentação oficial, adaptando-se à sua distribuição Linux. Por exemplo, para Ubuntu:

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu 
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
sudo curl -L "https://github.com/docker/compose/releases/download/v2.16.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Orquestração de Componentes com Docker Compose

Vamos configurar o Kong Gateway (com PostgreSQL como banco de dados) e o Keycloak utilizando um arquivo docker-compose.yml. Esta abordagem garante a reprodutibilidade do ambiente e simplifica a gestão dos serviços.

Configuração do Keycloak

O Keycloak será executado em um contêiner Docker. É crucial expor as portas necessárias e configurar variáveis de ambiente para a administração inicial.

version: '3.8'

services:
  keycloak:
    image: quay.io/keycloak/keycloak:21.1.2 # Ou versão mais recente
    command: start-dev --import-realm
    environment:
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
      KC_DB: postgres
      KC_DB_URL_HOST: keycloak-db
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: password
      KC_HTTP_PORT: 8080
    ports:
      - "8080:8080"
    volumes:
      - ./keycloak-realm:/opt/keycloak/data/import
    depends_on:
      - keycloak-db
    networks:
      - kong-keycloak-net

  keycloak-db:
    image: postgres:13
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: password
    volumes:
      - keycloak_db_data:/var/lib/postgresql/data
    networks:
      - kong-keycloak-net

  kong-database:
    image: postgres:13
    environment:
      POSTGRES_DB: kong
      POSTGRES_USER: kong
      POSTGRES_PASSWORD: kong
    volumes:
      - kong_db_data:/var/lib/postgresql/data
    networks:
      - kong-keycloak-net

  kong-migrations:
    image: kong:3.3.0-alpine
    command: kong migrations bootstrap
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-database
      KONG_PG_PASSWORD: kong
      KONG_PG_USER: kong
    depends_on:
      - kong-database
    networks:
      - kong-keycloak-net
    restart: on-failure

  kong:
    image: kong:3.3.0-alpine
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-database
      KONG_PG_USER: kong
      KONG_PG_PASSWORD: kong
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stderr
      KONG_ADMIN_ERROR_LOG: /dev/stderr
      KONG_ADMIN_LISTEN: 0.0.0.0:8001, 0.0.0.0:8444 ssl
      KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl
      KONG_PG_PORT: 5432
    ports:
      - "8000:8000" # Porta HTTP do proxy
      - "8443:8443" # Porta HTTPS do proxy
      - "8001:8001" # Porta HTTP da Admin API
      - "8444:8444" # Porta HTTPS da Admin API
    depends_on:
      - kong-migrations
    networks:
      - kong-keycloak-net

volumes:
  keycloak_db_data:
  kong_db_data:

networks:
  kong-keycloak-net:
    driver: bridge

Crie o diretório keycloak-realm e um arquivo realm.json dentro dele para importar automaticamente um realm inicial no Keycloak. Este arquivo pode conter um realm, um cliente e um usuário de teste.

Exemplo de keycloak-realm/realm.json:

{
  "realm": "minha-api-realm",
  "enabled": true,
  "clients": [
    {
      "clientId": "minha-api-client",
      "secret": "minha-api-secret",
      "enabled": true,
      "clientAuthenticatorType": "client-secret",
      "redirectUris": [
        "http://localhost:8000/callback",
        "http://localhost:8000/*",
        "http://kong:8000/callback",
        "http://kong:8000/*"
      ],
      "webOrigins": [],
      "publicClient": false,
      "protocol": "openid-connect",
      "fullScopeAllowed": true,
      
    }
  ],
  "users": [
    {
      "username": "apiuser",
      "enabled": true,
      "credentials": [
        {
          "type": "password",
          "value": "password",
          "temporary": false
        }
      ]
    }
  ]
}

Após criar o arquivo docker-compose.yml e o diretório keycloak-realm com o realm.json, inicie os serviços:

docker-compose up -d

Verifique o status dos contêineres:

docker-compose ps

Você deverá conseguir acessar o console de administração do Keycloak em http://localhost:8080/admin com as credenciais admin/admin. O realm minha-api-realm, o cliente minha-api-client e o usuário apiuser devem estar pré-configurados.

Configuração do Kong Gateway para OIDC

Com os serviços essenciais em execução, o próximo passo é configurar o Kong para integrar-se ao Keycloak usando o plugin OIDC. Isso envolve criar um Serviço, uma Rota e, finalmente, habilitar e configurar o plugin OIDC para essa Rota ou Serviço. Para este exemplo, usaremos a Admin API do Kong para configurar, embora em um ambiente de produção a abordagem declarativa (DEC) via kong.yml e deck seria preferível.

Definindo um Serviço e uma Rota de Exemplo

Vamos supor que temos um serviço de backend simples que desejamos proteger. Para fins de teste, podemos usar httpbin.org ou um serviço local.

# Criar um serviço no Kong para o backend de exemplo
curl -X POST http://localhost:8001/services 
  --data "name=httpbin-service" 
  --data "url=https://httpbin.org/anything"

# Criar uma rota para o serviço
curl -X POST http://localhost:8001/services/httpbin-service/routes 
  --data "paths[]=/api/v1/anything" 
  --data "strip_path=true"

Habilitando e Configurando o Plugin OIDC

Agora, ative o plugin OIDC na rota ou serviço que você deseja proteger. Para maior granularidade, é comum aplicar o plugin na Rota. Os parâmetros de configuração virão do seu cliente Keycloak e do próprio Keycloak IdP.

# Configurar o plugin OIDC na rota '/api/v1/anything'
# Note: keycloak é o nome do serviço docker-compose, que resolve para o IP interno do contêiner Keycloak.
# O host precisa ser acessível do Kong. Se for um ambiente fora do docker-compose, use o IP/hostname do Keycloak.

curl -X POST http://localhost:8001/routes/api-v1-anything/plugins 
  --data "name=openid-connect" 
  --data "config.client_id=minha-api-client" 
  --data "config.client_secret=minha-api-secret" 
  --data "config.issuer=http://keycloak:8080/realms/minha-api-realm" 
  --data "config.auth_methods=client_credentials,authorization_code" 
  --data "config.credential_location=header" 
  --data "config.redirect_uri=http://kong:8000/callback" 
  --data "config.bearer_only=false" 
  --data "config.token_introspection_endpoint=http://keycloak:8080/realms/minha-api-realm/protocol/openid-connect/token/introspect" 
  --data "config.introspection_key_claim=sub" 
  --data "config.introspection_value_claim=preferred_username"

Parâmetros chave:

  • config.client_id: ID do cliente Keycloak.
  • config.client_secret: Segredo do cliente Keycloak.
  • config.issuer: URL do emissor (Keycloak Realm URL).
  • config.redirect_uri: URL para onde o Keycloak redirecionará após a autenticação. Deve ser uma URL que o Kong pode interceptar (http://kong:8000/callback é o hostname do serviço Kong dentro da rede Docker Compose).
  • config.auth_methods: Define os fluxos OIDC permitidos.

Testando a Integração de Autenticação

Com o plugin OIDC ativado, tentar acessar a rota protegida sem autenticação resultará em um redirecionamento para o Keycloak para login (se bearer_only for false para o fluxo de código de autorização), ou em uma falha de autenticação se bearer_only for true para o fluxo de client credentials.

Fluxo Client Credentials

Este fluxo é ideal para comunicação serviço a serviço, onde um cliente (não um usuário final) precisa de acesso a uma API. O cliente usa seu client_id e client_secret para obter um token de acesso diretamente do Keycloak.

# 1. Obter um token de acesso do Keycloak usando Client Credentials
TOKEN_RESPONSE=$(curl -X POST "http://localhost:8080/realms/minha-api-realm/protocol/openid-connect/token" 
  -H "Content-Type: application/x-www-form-urlencoded" 
  -d "grant_type=client_credentials" 
  -d "client_id=minha-api-client" 
  -d "client_secret=minha-api-secret")

ACCESS_TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.access_token')

echo "Token de Acesso: $ACCESS_TOKEN"

# 2. Acessar a API protegida via Kong com o token
curl -X GET http://localhost:8000/api/v1/anything 
  -H "Authorization: Bearer $ACCESS_TOKEN"

A resposta esperada deve ser do serviço httpbin.org/anything, indicando que o Kong validou o token e encaminhou a requisição.

Fluxo Authorization Code (para usuários)

Para fluxos que envolvem um usuário final e um navegador, o fluxo de código de autorização é mais comum. O Kong iniciaria o redirecionamento para o Keycloak, o usuário faria login, e o Keycloak redirecionaria de volta para o Kong com um código, que o Kong trocaria por um token.

Para testar isso, você pode tentar acessar http://localhost:8000/api/v1/anything diretamente em um navegador. Você será redirecionado para a página de login do Keycloak. Após login (com apiuser/password), será redirecionado de volta ao Kong, que então mostrará a resposta da API.

Granularidade de Acesso com ACLs do Kong

Além da autenticação básica, o Kong permite implementar controle de acesso baseado em lista (ACL) utilizando informações dos tokens de acesso. O plugin OIDC do Kong pode extrair dados (claims) do token e mapeá-los para consumidores ou grupos de consumidores no Kong. Isso permite que você crie políticas de autorização mais refinadas.

Mapeando Claims para Consumidores

O plugin OIDC pode ser configurado para criar ou associar consumidores do Kong dinamicamente com base em claims do token. Por exemplo, você pode mapear o preferred_username do Keycloak para o username de um consumidor do Kong.

# Exemplo de configuração de um consumidor para o usuário 'apiuser'
# Idealmente, isto seria feito programaticamente ou via kong.yml/deck
curl -X POST http://localhost:8001/consumers 
  --data "username=apiuser"

# Associar o usuário 'apiuser' a um grupo de ACL
curl -X POST http://localhost:8001/consumers/apiuser/acls 
  --data "group=api_readers"

# Habilitar o plugin ACL na rota (ou serviço)
curl -X POST http://localhost:8001/routes/api-v1-anything/plugins 
  --data "name=acl" 
  --data "config.whitelist=api_readers"

Com esta configuração, somente tokens de usuários que pertencem ao grupo api_readers (ou seja, o consumidor apiuser) terão acesso à rota /api/v1/anything. A integração do plugin OIDC com o plugin ACL é poderosa para autorização baseada em atributos (ABAC).

Automação e Manutenção com Kong Declarative Configuration (DEC)

Para ambientes de produção, gerenciar configurações do Kong via Admin API de forma manual é inviável e propenso a erros. A abordagem recomendada é utilizar a configuração declarativa do Kong, com um arquivo YAML ou JSON que descreve o estado desejado da sua infraestrutura de API. Ferramentas como Kong deck (declarative config) permitem sincronizar esse arquivo com o estado do Kong Gateway.

Exemplo de kong.yml:

_format_version: "3.0"

services:
  - name: httpbin-service
    url: https://httpbin.org/anything
    routes:
      - name: api-v1-anything
        paths: [
          "/api/v1/anything"
        ]
        strip_path: true
        plugins:
          - name: openid-connect
            config:
              client_id: minha-api-client
              client_secret: minha-api-secret
              issuer: http://keycloak:8080/realms/minha-api-realm
              auth_methods: 
                - client_credentials
                - authorization_code
              credential_location: header
              redirect_uri: http://kong:8000/callback
              bearer_only: false
              token_introspection_endpoint: http://keycloak:8080/realms/minha-api-realm/protocol/openid-connect/token/introspect
              introspection_key_claim: sub
              introspection_value_claim: preferred_username
          - name: acl
            config:
              whitelist:
                - api_readers

consumers:
  - username: apiuser
    acls:
      - group: api_readers

Para aplicar essa configuração, primeiro copie o kong.yml para o contêiner do Kong ou um volume persistente. Então execute:

docker-compose exec kong kong deck sync -s kong.yml

Este comando sincronizará o estado do kong.yml com a configuração ativa do Kong. Esta metodologia é fundamental para integrar a gestão do Kong em pipelines de CI/CD, garantindo que as mudanças de configuração sejam versionadas, revisadas e aplicadas de forma automatizada.

Considerações de Resiliência e Segurança em Produção

Para um ambiente de produção, diversos fatores adicionais merecem atenção:

  • HTTPS/TLS: Todas as comunicações (Kong <-> Cliente, Kong <-> Keycloak, Keycloak <-> Cliente) devem ser protegidas por TLS. Configure certificados no Kong e Keycloak.
  • Segredos: Credenciais de banco de dados, segredos de clientes Keycloak e outros segredos não devem ser hardcoded. Utilize ferramentas de gerenciamento de segredos como HashiCorp Vault, Kubernetes Secrets (se em K8s), ou variáveis de ambiente seguras.
  • Alta Disponibilidade: Execute múltiplos nós do Kong e Keycloak, distribuídos em diferentes zonas de disponibilidade, para garantir resiliência contra falhas. Bancos de dados devem ser configurados com replicação e failover automático.
  • Monitoramento e Logs: Integre o Kong e Keycloak com sistemas de monitoramento (Prometheus, Grafana) e agregação de logs (ELK Stack, Grafana Loki) para visibilidade operacional e de segurança.
  • Auditoria: Configure o Keycloak para registrar eventos de auditoria detalhados, permitindo rastrear tentativas de login, alterações de permissão e outras ações críticas.
  • Atualizações e Patches: Mantenha Kong, Keycloak e o sistema operacional subjacente atualizados com os últimos patches de segurança.
  • Rede Segregada: Isole os componentes em redes privadas, expondo apenas o Kong Gateway para o tráfego externo.

Expandindo a Autorização com OPA/Rego

Para cenários de autorização mais complexos, onde as decisões não são binárias (permitir/negar) mas dependem de múltiplos atributos da requisição, do usuário e do recurso, a integração com o Open Policy Agent (OPA) é uma excelente evolução. O Kong pode ser configurado para enviar informações da requisição para um serviço OPA, que avaliaria as políticas de Rego e retornaria uma decisão de autorização. Esta abordagem desacopla a lógica de autorização da sua API Gateway e dos seus microsserviços, promovendo maior flexibilidade e reusabilidade de políticas.

A implementação de segurança de APIs com Kong Gateway e Keycloak no Linux estabelece uma base sólida para qualquer arquitetura de microsserviços. Adotando práticas DevOps e infraestrutura como código, é possível construir um sistema seguro, escalável e de fácil manutenção, capaz de proteger recursos valiosos contra acessos não autorizados e ataques maliciosos.