Proteção Robusta de APIs: Kong Gateway e Keycloak no Linux

A segurança de APIs é uma camada crítica na arquitetura de microsserviços e aplicações distribuídas. O cenário atual exige mecanismos de autenticação e autorização robustos, escaláveis e de fácil gerenciamento. A combinação do Kong Gateway, atuando como um poderoso proxy de API e orquestrador de tráfego, com o Keycloak, uma solução de Gerenciamento de Identidade e Acesso (IAM) de código aberto, oferece uma arquitetura resiliente e flexível para proteger endpoints de API em ambientes Linux. Este artigo detalha a implementação e configuração dessa sinergia, focando em práticas de DevOps, automação e infraestrutura como código.

Fundamentos de Arquitetura para Segurança de APIs

A estratégia aqui consiste em delegar a autenticação de usuários e clientes de API ao Keycloak, utilizando padrões como OAuth 2.0 e OpenID Connect (OIDC). O Kong Gateway, posicionado na borda da rede, intercepta todas as requisições destinadas às APIs. Sua função primária é validar tokens de acesso emitidos pelo Keycloak antes que qualquer requisição atinja o serviço de backend, garantindo que apenas tráfego autorizado e autenticado prossiga. Essa abordagem centraliza a lógica de segurança, reduzindo a complexidade nos serviços de backend e promovendo a reutilização de código.

Componentes Essenciais

  • Keycloak: Servidor de autenticação e autorização que gerencia identidades, emite e valida tokens JWT (JSON Web Token), e suporta fluxos OAuth 2.0 e OIDC.
  • Kong Gateway: API Gateway de alto desempenho que atua como proxy reverso, balanceador de carga, e, crucialmente, como ponto de imposição de políticas de segurança (via plugins).
  • Serviços de Backend: As APIs que precisam ser protegidas. O Kong as expõe e as protege, enquanto o Keycloak garante que apenas entidades autorizadas possam interagir com elas.
  • PostgreSQL: Banco de dados relacional robusto, utilizado tanto pelo Keycloak quanto pelo Kong para persistir suas configurações e dados de runtime.

Preparando o Ambiente Linux para Implantação

Para uma implantação eficiente e replicável, utilizaremos Docker e Docker Compose. Isso facilita o empacotamento das dependências e a orquestração dos contêineres. Certifique-se de que o sistema operacional Linux (por exemplo, Ubuntu Server, CentOS, Debian) esteja atualizado e com Docker e Docker Compose instalados.

Instalação do Docker e Docker Compose (Exemplo no Ubuntu)

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
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 usermod -aG docker $USER # Adicione seu usuário ao grupo docker
newgrp docker # Ative as novas permissões (ou reinicie a sessão)

sudo curl -L "https://github.com/docker/compose/releases/download/v2.19.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

docker --version
docker-compose --version

Implantação do Keycloak via Docker Compose

Vamos configurar o Keycloak junto a um banco de dados PostgreSQL persistente. Crie um diretório de projeto e, dentro dele, um arquivo docker-compose.yml.

docker-compose.yml para Keycloak e PostgreSQL

# keycloak-compose.yml
version: '3.8'

services:
  keycloak-db:
    image: postgres:13
    restart: always
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: ${DB_PASSWORD_KEYCLOAK:-admin}
    volumes:
      - ./data/keycloak-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U keycloak"]
      interval: 10s
      timeout: 5s
      retries: 5

  keycloak:
    image: quay.io/keycloak/keycloak:21.1.2
    restart: always
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://keycloak-db:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: ${DB_PASSWORD_KEYCLOAK:-admin}
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin}
      KC_HOSTNAME: localhost
      KC_HTTP_PORT: 8080
      KC_PROXY: edge # Importante para integrar com gateways/proxies
      KC_LOG_LEVEL: INFO
    ports:
      - "8080:8080"
    command: start --optimized --hostname-strict=false # Desabilita hostname strict para desenvolvimento
    depends_on:
      keycloak-db:
        condition: service_healthy
    volumes:
      - ./data/keycloak-config:/opt/keycloak/conf

volumes:
  keycloak-db:
  keycloak-config:

Este arquivo configura um serviço de banco de dados PostgreSQL e o Keycloak. As variáveis de ambiente DB_PASSWORD_KEYCLOAK e KEYCLOAK_ADMIN_PASSWORD devem ser definidas no ambiente ou substituídas por valores seguros no arquivo. O parâmetro KC_PROXY: edge é crucial para que o Keycloak funcione corretamente atrás de um proxy reverso como o Kong.

Para iniciar o Keycloak:

mkdir -p data/keycloak-db data/keycloak-config
docker-compose -f keycloak-compose.yml up -d

Aguarde alguns minutos para que o Keycloak inicie completamente. O painel de administração estará acessível em http://localhost:8080 com as credenciais admin/admin (ou as que você definiu).

Configuração Inicial do Keycloak

Após iniciar, configure o Keycloak. É uma boa prática automatizar isso com a CLI do Keycloak ou scripts de importação de realm JSON, mas para fins de demonstração, podemos fazer manualmente:

  1. Crie um novo Realm (ex: minha-api-realm).
  2. Dentro do Realm, crie um Cliente (ex: kong-client) com as seguintes configurações:
    • Client type: OpenID Connect
    • Access type: confidential
    • Standard flow enabled: ON (para testes)
    • Service accounts enabled: ON (para o Kong obter tokens)
    • Valid redirect URIs: * (para testes, em produção seja específico)
    • Web origins: * (para testes, em produção seja específico)
  3. Na aba ‘Credentials’ do cliente, copie o ‘Secret’ gerado. Ele será usado pelo Kong.
  4. Crie um Usuário (ex: apiuser) com uma senha.

Configuração do Kong Gateway via Docker Compose

Agora, implante o Kong Gateway. Ele também usará o PostgreSQL para persistência. Crie um novo arquivo kong-compose.yml no mesmo diretório.

kong-compose.yml para Kong e PostgreSQL

# kong-compose.yml
version: '3.8'

services:
  kong-db:
    image: postgres:13
    restart: always
    environment:
      POSTGRES_DB: kong
      POSTGRES_USER: kong
      POSTGRES_PASSWORD: ${DB_PASSWORD_KONG:-kongpass}
    volumes:
      - ./data/kong-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U kong"]
      interval: 10s
      timeout: 5s
      retries: 5

  kong-migrations:
    image: kong:3.3.0-alpine
    command: kong migrations bootstrap
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-db
      KONG_PG_PORT: 5432
      KONG_PG_USER: kong
      KONG_PG_PASSWORD: ${DB_PASSWORD_KONG:-kongpass}
      KONG_PG_DATABASE: kong
    depends_on:
      kong-db:
        condition: service_healthy
    restart: on-failure

  kong:
    image: kong:3.3.0-alpine
    restart: always
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: kong-db
      KONG_PG_PORT: 5432
      KONG_PG_USER: kong
      KONG_PG_PASSWORD: ${DB_PASSWORD_KONG:-kongpass}
      KONG_PG_DATABASE: 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_ANONYMOUS_REPORTS: "off"
    ports:
      - "80:8000"   # HTTP para o proxy
      - "443:8443" # HTTPS para o proxy
      - "8001:8001" # HTTP para a API Admin
      - "8444:8444" # HTTPS para a API Admin
    depends_on:
      kong-migrations:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:8001/status || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  kong-db:

Inicie o Kong Gateway:

mkdir -p data/kong-db
docker-compose -f kong-compose.yml up -d

Verifique o status do Kong em http://localhost:8001. Ele deve retornar uma resposta JSON com as informações do Gateway.

Integrando Kong com Keycloak para Autenticação OIDC

Com Keycloak e Kong em execução, o próximo passo é configurar o Kong para usar o Keycloak como provedor de identidade via OIDC. Para isso, criaremos um serviço e uma rota no Kong, e aplicaremos o plugin OpenID Connect a essa rota.

Exemplo de Serviço de API (Mock Server)

Para testar, podemos usar um simples mock server ou qualquer serviço de backend que responda a requisições HTTP.

# mock-api-compose.yml
version: '3.8'

services:
  mock-api:
    image: mendhak/http-https-server
    environment:
      HTTP_PORT: 80
      CORS: "true"
    ports:
      - "8081:80"
    restart: always
docker-compose -f mock-api-compose.yml up -d

Este mock API estará disponível em http://localhost:8081.

Configurando Serviço e Rota no Kong via CLI

Crie um Serviço no Kong que aponte para o nosso mock-api e uma Rota que exponha este serviço através do Kong.

# Criar Serviço para a API de backend
curl -X POST http://localhost:8001/services 
  --data name='minha-api-backend' 
  --data url='http://mock-api:80'

# Criar Rota para o Serviço (o tráfego para /minha-api será roteado para o serviço)
curl -X POST http://localhost:8001/services/minha-api-backend/routes 
  --data paths[]='/minha-api'

Agora, você pode acessar a API via Kong (sem autenticação ainda): http://localhost/minha-api (isso deve mostrar a resposta do mock-api).

Aplicando o Plugin OpenID Connect do Kong

O plugin openid-connect do Kong fará a integração com o Keycloak. Ele intercepta as requisições, redireciona o usuário para o Keycloak para autenticação e, após o sucesso, valida o JWT recebido. Configure o plugin na rota minha-api.

# Plugin OpenID Connect configurado na rota
KEYCLOAK_CLIENT_SECRET='<O SECRET GERADO PELO KEYCLOAK PARA O CLIENTE KONG-CLIENT>'

curl -X POST http://localhost:8001/routes/minha-api/plugins 
  --data name='openid-connect' 
  --data config.client_id='kong-client' 
  --data config.client_secret="$KEYCLOAK_CLIENT_SECRET" 
  --data config.issuer='http://localhost:8080/realms/minha-api-realm' 
  --data config.realm='minha-api-realm' 
  --data config.introspection_endpoint='http://keycloak:8080/realms/minha-api-realm/protocol/openid-connect/token/introspect' 
  --data config.auth_methods='bearer,authorization_code' 
  --data config.cookie_secret='super-secret-cookie-key-with-32-chars!' 
  --data config.upstream_headers_claim_names='preferred_username,email,sub' 
  --data config.public_key_cache_ttl=3600 
  --data config.access_token_param_names='access_token'

Substitua <O SECRET GERADO PELO KEYCLOAK PARA O CLIENTE KONG-CLIENT> pelo valor real do secret do seu cliente Keycloak. Note que o cookie_secret deve ter 32 caracteres (ou 64/128 para maior segurança).

Testando o Fluxo de Autenticação

Ao tentar acessar http://localhost/minha-api agora, o Kong deve redirecionar você para a página de login do Keycloak. Após o login bem-sucedido com apiuser, você será redirecionado de volta para http://localhost/minha-api, e a resposta do mock-api será exibida. O Kong adicionará cabeçalhos na requisição upstream com informações do JWT, como X-Consumer-Username e outros claims configurados em upstream_headers_claim_names.

Automação e Infraestrutura como Código (IaC)

Gerenciar configurações do Kong e Keycloak manualmente é inviável em ambientes de produção. A adoção de IaC é fundamental.

Kong Declarative Configuration (DEC)

O Kong suporta configuração declarativa via um arquivo YAML (kong.yml). Isso permite versionar todas as suas configurações de serviços, rotas e plugins em um repositório Git e aplicá-las ao Kong.

Exemplo de kong.yml

_format_version: "3.0"

services:
  - name: minha-api-backend
    url: http://mock-api:80
    routes:
      - name: minha-api-route
        paths:
          - /minha-api
        plugins:
          - name: openid-connect
            config:
              client_id: kong-client
              client_secret: <O SECRET GERADO PELO KEYCLOAK PARA O CLIENTE KONG-CLIENT>
              issuer: http://localhost:8080/realms/minha-api-realm
              realm: minha-api-realm
              introspection_endpoint: http://keycloak:8080/realms/minha-api-realm/protocol/openid-connect/token/introspect
              auth_methods: bearer,authorization_code
              cookie_secret: super-secret-cookie-key-with-32-chars!
              upstream_headers_claim_names: preferred_username,email,sub
              public_key_cache_ttl: 3600
              access_token_param_names: access_token

Para aplicar este arquivo ao Kong:

docker cp kong.yml kong:/kong.yml
docker exec kong kong config reload -c /kong.yml # Ou usar `kong config push` se a API Admin estiver acessível externamente

Automação do Keycloak

O Keycloak permite exportar realms como arquivos JSON, que podem ser versionados. Para automatizar a criação de realms, clientes e usuários, pode-se usar a CLI do Keycloak (kcadm.sh) ou ferramentas como Terraform com o provedor Keycloak.

Exemplo de criação de Realm com Terraform

# main.tf
resource "keycloak_realm" "minha_api_realm" {
  realm              = "minha-api-realm"
  enabled            = true
  display_name       = "Realm para Minhas APIs"
  access_code_lifespan = "300s"
}

resource "keycloak_openid_client" "kong_client" {
  realm_id                     = keycloak_realm.minha_api_realm.id
  client_id                    = "kong-client"
  name                         = "Kong Gateway Client"
  enabled                      = true
  access_type                  = "CONFIDENTIAL"
  service_accounts_enabled     = true
  standard_flow_enabled        = true
  valid_redirect_uris          = ["*"] # Ajustar em produção
  web_origins                  = ["*"] # Ajustar em produção
  client_secret                = "${var.keycloak_kong_client_secret}"
}

variable "keycloak_kong_client_secret" {
  description = "O segredo do cliente para o Kong Gateway no Keycloak."
  type        = string
  sensitive   = true
}

Considerações de Produção e Boas Práticas

  • Segurança de Credenciais: Nunca armazene secrets diretamente em arquivos de configuração ou repositórios Git. Utilize ferramentas de gerenciamento de segredos como HashiCorp Vault, AWS Secrets Manager, ou variáveis de ambiente seguras.
  • HTTPS/TLS: Sempre configure HTTPS para o Kong Gateway e para o Keycloak. Utilize certificados TLS válidos (Let’s Encrypt, certificados corporativos). O Kong suporta a terminação TLS e o plugin acme para Let’s Encrypt.
  • Alta Disponibilidade: Em produção, o Kong e o Keycloak devem ser implantados em clusters para alta disponibilidade, com balanceadores de carga adequados e múltiplos nós para os bancos de dados.
  • Observabilidade: Implemente monitoramento (Prometheus, Grafana), logging centralizado (ELK Stack, Splunk) e tracing distribuído (Jaeger, Zipkin) para diagnosticar problemas e garantir o desempenho.
  • Políticas de Autorização: Além da autenticação OIDC, o Kong pode aplicar políticas de autorização mais granulares usando plugins como o opa (Open Policy Agent) ou acl, baseando-se em grupos, roles ou claims presentes no JWT.
  • Limite de Taxa e Proteção contra DoS: Configure plugins como rate-limiting e ip-restriction no Kong para proteger suas APIs contra abusos e ataques DoS.

Refinamento da Segurança com Roles e Scopes

A simples validação de um token JWT garante que a requisição é autenticada. Para autorização, é essencial verificar se o usuário ou cliente tem permissão para acessar um recurso específico ou executar uma ação. Keycloak facilita isso com roles e scopes.

  • Roles (Papéis): Podem ser atribuídas a usuários ou grupos no Keycloak. Quando um token é emitido, os papéis do usuário são incluídos como claims (geralmente no campo realm_access.roles ou resource_access.<client_id>.roles).
  • Scopes: Definem o escopo de acesso que um cliente está solicitando. Por exemplo, um cliente pode solicitar o scope read ou write. Estes scopes também são incluídos no JWT.

O Kong Gateway pode ser configurado para inspecionar esses claims do JWT. O plugin openid-connect do Kong pode ser estendido com regras de autorização personalizadas, ou plugins adicionais como o jwt (para validação mais simples) ou o opa (Open Policy Agent) para lógica de autorização complexa. Para um controle mais refinado, pode-se desenvolver um plugin customizado para o Kong que interaja com um serviço de autorização externo.

Por exemplo, para um cenário onde apenas usuários com o role admin podem acessar uma rota:

# Exemplo (conceitual, exigiria um plugin customizado ou OPA para lógica complexa)
# Adicionar o role 'admin' a um usuário no Keycloak
# ...

# Plugin hipotético para verificar roles (ou usar OPA)
curl -X POST http://localhost:8001/routes/minha-api/plugins 
  --data name='role-based-authorization' 
  --data config.required_roles='admin'

A arquitetura com Kong e Keycloak fornece uma base sólida para construir camadas de segurança avançadas, desde a autenticação básica até políticas de autorização complexas baseadas em atributos e contexto. A flexibilidade do Kong em termos de plugins e a robustez do Keycloak tornam essa combinação ideal para ambientes Linux exigentes.