DevSecOps

17 mar, 2017

Escale a conexão única para seus aplicativos em nuvem Node.js

Publicidade

O design do aplicativo de escala em nuvem bem-sucedido requer planejamento para como atingir corretamente a escala horizontal em componentes de aplicativos e serviços. Neste artigo, você cria um aplicativo simples em Node.js em Bluemix, que usa o serviço IBM Single Sign On. Você vê o que acontece quando o aplicativo é escalado além de uma única instância e tenta autenticar (dica: as coisas não vão bem). Em seguida, explicarei o que deu errado e guiarei você em uma implementação para corrigir o erro, com a ajuda do serviço Redis Cloud em Bluemix.

O que você precisará para concluir este artigo:

  • Uma conta Bluemix
  • Uma estação de trabalho com o seguinte software instalado:
    • Git (para clonar o repositório de aplicativo base)
    • A função Interface da linha de comandos Cloud Foundry versão 6.5 ou mais recente
    • Um editor de texto para fazer atualizações menores no código-fonte de origem fornecido.

Quando você executar meu aplicativo demo, conecte-se com o nome do usuário clouduser e a senha Bluemix123.

Etapa 1. Configure o aplicativo inicial

Sua primeira tarefa é criar um aplicativo simples Node.js em Bluemix que usa o serviço Single Sign On. Você irá criar um novo aplicativo, incluir e configurar uma instância de serviço Single Sign On, ligar o serviço ao aplicativo e especificar a URL de retorno de chamada.

  • Efetue login no Bluemix, clique em CREATE APP e selecione WEB como o tipo de aplicativo;
  • Clique em SDK para Node.js e, em seguida, clique em CONTINUAR;
  • Especifique um nome exclusivo para seu aplicativo. Por exemplo, é possível iniciar o nome com scaleSSO seguido por um hífen e, em seguida, torná-lo exclusivo, incluir suas iniciais e a data, como em scaleSSO-TOR0815:

  • No restante deste artigo, substitua o <nome de seu aplicativo> pelo nome que inseriu aqui;
  • Clique em CONCLUIR. Aguarde enquanto o Bluemix organiza e executa seu aplicativo;
  • Clique em VISUALIZAR VISÃO GERAL DO APLICATIVO (na parte inferior da página);
  • Na página de visão geral do aplicativo, clique no botão PARAR e confirme. É necessário incluir algum código no aplicativo para que ele funcione com o serviço Single Sign On;
  • Acesse o Catálogo Bluemix e clique em Conexão Única na seção de serviços Segurança:

  • Escolha Deixar desvinculado na lista suspensa Aplicativo e clique em CRIAR. Aguarde até que o serviço seja criado e o gerenciador de configuração do serviço seja iniciado;
  • Digite scaleSSOtest como o nome do serviço e clique em Continuar:

  • Na página que solicita uma nova origem de identidade, clique em Diretório de nuvempara incluir uma origem de identidade simples;
  • Clique no ícone de mais para incluir um novo usuário;
  • Na caixa de diálogo Incluir usuário, insira um nome de usuário e senha de sua escolha, juntamente com os outros atributos do perfil. Clique em Salvar para incluir o usuário e, em seguida, clique em Salvar para fechar o painel de edição da origem de identidade:

  • Clique em Voltar ao painel e clique em seu aplicativo para abrir sua página de visão geral;
  • Na visão geral do aplicativo, clique em LIGAR UM SERVIÇO OU API;
  • Selecione o botão de opções para o serviço Single Sign On que você acabou de criar e clique em INCLUIR:

  • Clique no ícone de divisa em V à direita do link Voltar ao painel e clique no serviço Single Sign On no menu suspenso:

Clique novamente no ícone de divisa em V para sair do menu suspenso.

  • Clique no botão INTEGRAR na parte superior direita do gerenciador de configuração do Single Sign On;
  • No campo Retornar à URL, insira: https://<nome de seu aplicativo>.mybluemix.net/auth/sso/callback;
  • Clique no botão Salvar e depois clique em OK;
  • Clique em Voltar ao painel.

A configuração inicial de seu aplicativo está concluída.

Etapa 2. Modifique o código do aplicativo e reimplemente

Nesta etapa, você irá clonar um projeto do IBM DevOps Services que tenha o aplicativo simples Node.js configurado como usar o Single Sign On. Modifique esse código para usá-lo para seu aplicativo existente e, então, envie por push o código para o Bluemix implementar o aplicativo.

  • Abra um prompt de comandos em sua estação de trabalho local e execute este comando:clone git https://hub.jazz.net/git/timro/scaleSSO-base <nome de seu aplicativo>
  • Usando um editor de texto, atualize o arquivo app.js no novo diretório criado pelo clone git. Na linha 49 no arquivo, mude o callback_url para corresponder ao valor Retornar à URL que você usou na Etapa 1 (Subetapa 18):
// you MUST change the host route to match your application name
var callback_url = 'https://<nome de seu aplicativo>.mybluemix.net/auth/sso/callback';

Atualize o arquivo manifest.yml, substituindo o host do aplicativo e as propriedades de nome:

aplicativos:
- disk_quota: 1024M
  host: <nome de seu aplicativo>
  nome: <nome de seu aplicativo>
  caminho: .
  domínio: mybluemix.net
  • Mude o diretório ativo da linha de comandos para o diretório do projeto e efetue login no Bluemix com a ferramenta de linha de comandos Cloud Foundry:cf login -a https://api.ng.bluemix.net
  • Atualize e implemente seu aplicativo no Bluemix executando:cf push
  • Observe as mensagens de preparação do cf push. Após implementar, o aplicativo será iniciado e você verá um estado de execução para a instância do aplicativo:

O aplicativo agora está pronto para teste.

Etapa 3. Escalar o aplicativo em Bluemix

Nesta etapa, você irá testar a autenticação de seu aplicativo — primeiro com uma instância de aplicativo única e depois com uma segunda instância incluída.

  • Em uma nova janela ou guia do navegador, abra a URL para seu aplicativo: https://<your app name>.mybluemix.net. Clique no botão Login;
  •  Digite o nome do usuário e senha que você incluiu no Cloud Directory ao configurar o serviço Single Sign On e clique em Login. Se for solicitado a fazer isto, mude a senha inicial para uma nova:

Você receberá uma saudação que combina o nome do usuário autenticado e o domínio da autenticação — por exemplo, “Olá, scalessotest-nw2nz9occb-ck11.iam.ibmcloud.com/www.ibm.com/clouduser!” — indicando que você foi autenticado com êxito para essa instância do aplicativo.

  • Retorne ao painel do Bluemix para escalar o aplicativo. Abra a visão geral do aplicativo e clique no botão ^ em Instâncias para incrementar o número 2 da instância e clique em SALVAR;
  • O Bluemix inicia a segunda instância. Se você passar o mouse sobre a seção APP HEALTH, será possível ver que essas duas instâncias estão ativas;
  • Feche a sessão do navegador que você usou para testar o Single Sign On e abra uma nova janela ou guia do navegador. Navegue até https://<nome de seu aplicativo>.mybluemix.net e clique em Login. Autentique-se no Single Sign On e aceite compartilhar as informações pessoais, se solicitado;
  • Em vez da saudação simples, muito provavelmente você verá uma página “404 não localizado” ou uma mensagem de erro como “Não é possível OBTER /auth/sso/callback?scope=openid&code=EuPWIJBuCQdDjFbnGtgIAUsCiacMdE.”

Etapa 4. Entenda os resultados do teste

O aplicativo simples não teve problemas de autenticação com uma instância única, mas duas instâncias são um problema porque esse aplicativo não segue a metodologia aplicativo de doze fatores. Especificamente, ela viola o fator 6: “Execute o aplicativo como um ou mais processos stateless”.

Essa falha não intencional é por produto de como os aplicativos Node.js em Bluemix usam o Passaporte e o middleware express-session para fornecer suporte ao OpenID Connect para o serviço Single Sign On para Bluemix. O serviço express-session armazena os dados da sessão na memória, de modo que fiquem disponíveis somente para uma das duas instâncias. Quando o serviço Single Sign On redireciona o navegador para a URL de retorno de chamada depois de autenticar o usuário, se o navegador for encaminhado para outra instância, o mecanismo da web Expresso falhará ao consultar o ID da sessão para o usuário autenticado e vai até a mensagem 404.

Este diagrama ilustra como os dados de uma sessão estão disponíveis somente para a Instância 0 no aplicativo:

Qual é a solução? O Fator 6 aparece com os dizeres: “Qualquer dado que precise persistir deve ser armazenado em um serviço de retorno stateful, geralmente um banco de dados”. A documentação express-session no GitHub lista diversos armazenamentos auxiliares compatíveis. Você implementará essa persistência usando Redis, o qual fornece um cache de valor chave na memória. Essa mudança moverá os dados da sessão para express-session fora da memória da instância e para um armazenamento persistente disponível para todas as instâncias:

Etapa 5. Inclua a persistência de sessão com Redis

O serviço Redis Cloud em Bluemix é hospedado no mesmo ambiente SoftLayer que seu aplicativo, minimizando o tempo de resposta para acessar esse serviço de retorno.

  • Em Bluemix, acesse o catálogo e escolha Redis Cloud na categoria Dados e Analytics:

  • Escolha seu aplicativo Single Sign On na lisvta Aplicativo e 30 MB na lista Plano selecionado (não há encargo para esse plano e ele está cheio de espaço para as sessões neste tutorial);
  • Clique em CRIAR para incluir o serviço e ligá-lo ao seu aplicativo;
  • Clique em REMONTAR para concluir a inclusão do serviço em seu aplicativo;
  • Em sua cópia local do código-fonte do aplicativo, atualize a seção dependências em package.json incluindo uma vírgula na linha 14 e mais duas entradas:
  "passport-idaas-openidconnect": "1.0.x",
  "connect-redis": "2.4.x",
  "redis": "0.12.1"
},
  • Em app.js, inclua redis e connect-redis na seção requer, anexando na linha 17:
var OpenIDConnectStrategy = require('passport-idaas-openidconnect').IDaaSOIDCStrategy;
var redis = require('redis');
var RedisStore = require('connect-redis')(session);
  • Na linha 29, inclua o código para obter os detalhes de configuração para o serviço Redis Cloud a partir do ambiente e conecte-se ao serviço:
// get configuration for redis backing service and connect to service
var redisConfig = appEnv.getService(/Redis.*/)
var redisPort = redisConfig.credentials.port;
var redisHost = redisConfig.credentials.hostname;
var redisPasswd = redisConfig.credentials.password;

var redisclient = redis.createClient(redisPort, redisHost, {no_ready_check: true});
redisclient.auth(redisPasswd, function (err) {
    if (err) {
      throw err;
    }
});

redisclient.on('connect', function() {
    console.log('Connected to Redis');
});
  • Comente a instrução original app.use(session(… statement following the app.use(cookieParser()) ao lado da linha 48 e substitua-a por um bloco para inicializar a express-session usando Redis como o armazenamento:
// define express-session services, etc. for SSO

app.use(cookieParser());
// app.use(session({resave: 'true', saveUninitialized: 'true' , secret: 'keyboard cat'}));
app.use(session({
  store: new RedisStore({ client: redisclient }),
  resave: 'true',
  saveUninitialized: 'true',
  secret: 'top secr8t'
}));
app.use(passport.initialize());
app.use(passport.session());
  • Salve app.js e package.json se você não tiver feito isso ainda;
  • Na linha de comandos, atualize o aplicativo: cf push;
  • Após iniciar o aplicativo, use o comando logs do Cloud Foundry com a opção recent: cf logs <your app name> –recent;
  • Verifique a mensagem de que o aplicativo foi conectado ao Redis na inicialização:

  • O arquivo manifest.yml especifica somente uma instância, portanto, o aplicativo foi iniciado com uma única instância. Use a visão geral do aplicativo para aumentar o número de instâncias para duas e salve a mudança;
  • Retorne ao aplicativo em https://<nome de seu aplicativo>.mybluemix.net/ e repita o teste de login a partir da Etapa 3.

Sucesso! Agora o aplicativo funciona corretamente com duas instâncias (ou mais).

Conclusão

Neste artigo, você criou um aplicativo simples que usa o serviço Single Sign On para Bluemix e depois testou o aplicativo com uma e duas instâncias em execução. Com duas instâncias, o aplicativo teve uma falha porque o middleware express-session do Node.js foi padronizado para um armazenamento na memória local.

Você corrigiu o problema incluindo um armazenamento persistente para as sessõesexpress-session, usando o serviço Redis Cloud em Bluemix. Este artigo destaca um princípio de design chave para escalar aplicativos em nuvem através do modelo de processo. Para atingir um ajuste de escala ótimo, cada processo deve ser projetado para ser stateless e sempre persistir os dados para um serviço de apoio disponível a todos os processos.