Okta como PHP moderno: Parte 3/3

okta

Okta como PHP moderno (Parte 3)

Inicio de sesión único para todas sus aplicaciones web con Okta.

Okta


Una de las cosas que se aprende a lo largo de los años es que sus aplicaciones no manejan la seguridad. Deje que los expertos se encarguen de la seguridad. Las aplicaciones pueden ser lo suficientemente complicadas sin tener que terminar SSL o autenticar a los usuarios. Además, dificulta las pruebas en un entorno de desarrollo. Intentar mantener su entorno PHP parcheado con las últimas correcciones de seguridad es mucho más difícil que darles un único punto de entrada como Nginx y mantenerlo parcheado.

En mis artículos anteriores de esta serie (consulte los enlaces a continuación), creé una aplicación PHP que le permite enumerar y agregar maridajes de vino y queso. También mostré cómo implementarlo en la nube y tenerlo disponible en Internet. Luego lo eliminé de inmediato, ya que tener una aplicación no segura en vivo en Internet es generalmente una mala idea. Entonces, en este artículo, no solo agregaré una pantalla de inicio de sesión, sino que la crearé para que la autenticación esté fácilmente disponible para cualquier aplicación que se ejecute en su VM en la nube.

Para reducir aún más la cantidad de trabajo que tiene que hacer, usaré un servicio llamado Okta para manejar la autenticación. También voy a utilizar una aplicación llamada Vouch como intermediario entre Nginx y Okta. Lo único que le preocupará a su aplicación es la autorización (permitir que ciertos usuarios tengan acceso a datos específicos del usuario). Se agregará una cookie segura con un JWT a cada solicitud y la aplicación puede usarla para determinar si un usuario en particular puede acceder o modificar los datos.

Lo primero que debe hacer es configurar una cuenta de desarrollador de Okta. Esta es una cuenta gratuita que permitirá registrar hasta 1000 usuarios. Una vez que haya iniciado sesión, cree una nueva aplicación y elija Web como tipo.

okta

A continuación, lo llevará a una pantalla de configuración donde agregará todos los URI necesarios para interactuar con su sistema. Dado que solo utilizará la aplicación Vouch, deberá crear un nuevo host en su dominio. Suponiendo que su dominio es “tudominio.com”, puede utilizar https://vouch.yourdomain.com como host para cada uno de estos elementos. El resto se puede dejar por defecto.

okta

Después de crear la aplicación, le dará una identificación de cliente y un secreto de cliente.

okta

La identificación del cliente es de conocimiento público, pero el secreto del cliente es, por supuesto, secreto. Deberá tener ambos como parámetros para su instancia de aval. La única otra información que necesitará es la URL de la organización Okta que puede encontrar en la esquina superior derecha del panel de Okta.

Ahora que tenemos la aplicación Vouch SSO configurada en el panel de Okta, implementemos Vouch en la nube. En mi caso, lo voy a poner en la misma VM con mi aplicación y Nginx. En los casos en los que proporcionará autenticación a varias aplicaciones, la configuración será más compleja. Pero comencemos aquí con una aplicación que se ejecuta en la misma VM. Si siguió mis artículos anteriores de esta serie, ya debería tener un repositorio llamado phpappprod. Si no, puede clonar el repositorio en su unidad local. Podemos iniciar Vouch agregándolo a nuestro docker-compose.yml.

vouch:
    image: voucher/vouch-proxy
    volumes:
      - ..:/config
    ports:
      - 9090:9090

Estoy usando la misma estrategia de mantener secretos en el directorio principal del repositorio para que no se registre en GitHub. La configuración estará en un archivo llamado ../config.yml (relativo al directorio del repositorio). Contendrá toda la configuración de Vouch y se verá así:

vouch:
  logLevel: debug
  domains:
  - vouch
  - {yourdomain}
oauth:
  provider: oidc
  client_id: {your client ID}
  client_secret: {your client secret}
  auth_url: https://{organizationURL}/oauth2/default/v1/authorize
  token_url: https://{organizationURL}/oauth2/default/v1/token
  user_info_url: https://{organizationURL}/oauth2/default/v1/userinfo
  scopes:
    - openid
    - profile
    - email
  # Set the callback URL to the domain that Vouch is running on
  callback_url: https://vouch.{yourdomain}/auth

El oauth.callback_url debe coincidir exactamente con el URI de redireccionamiento de inicio de sesión que especificó en la configuración de Okta. Tenga en cuenta también que agregué vouch a los dominios para poder acceder a Vouch directamente sin tener que ser redirigido a través de Internet.

Puede iniciarlo con docker-compose up up solo para probarlo. No funcionará todavía, ya que solo está configurado para funcionar en el dominio real, no localmente. Puede agregar dominios adicionales a su configuración para realizar pruebas, pero solo ejecutaremos la autenticación en el mundo real. Para probar localmente, asumiremos que todo ha sido autenticado. Ese es uno de los beneficios de mantener la autenticación fuera de la aplicación.

Antes de mover todo esto a la nube, tenemos que ajustar Nginx no solo para invertir el proxy de nuestra aplicación, sino también para invertir el proxy de la aplicación de garantía. Además, debería evitar el acceso a nuestra aplicación si no está autenticado y redirigir a Okta para iniciar sesión correctamente si es necesario. Esto es lo que se me ocurrió:

error_log debug;
events {}
http {
  server {
    listen 443 ssl;
    server_name vouch.kamradtfamily.net;

    ssl_certificate /etc/certs/kamradtfamily.net.pem;
    ssl_certificate_key /etc/certs/kamradtfamily.net.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Proxy to your Vouch instance
    location / {
      proxy_set_header  Host $http_host;
      proxy_set_header  X-Forwarded-Proto https;
      proxy_pass        http://vouch:9090;
    }
  }
  server {
    listen 443 ssl;
    server_name phpdemo.kamradtfamily.net;
    ssl_certificate /etc/certs/kamradtfamily.net.pem;
    ssl_certificate_key /etc/certs/kamradtfamily.net.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;
    auth_request /vouch-validate;

    location = /vouch-validate {
      # This address is where Vouch will be listening on
      proxy_pass http://vouch:9090/validate;
      proxy_pass_request_body off; # no need to send the POST body

      proxy_set_header Content-Length "";
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;

      # these return values are passed to the @error401 call
      auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
      auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
      auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
    }

    error_page 401 = @error401;

    # If the user is not logged in, redirect them to Vouch's login URL
    location @error401 {
      return 302 https://vouch.kamradtfamily.net/login?url=https://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
    }
    location / {
        proxy_pass http://phpapp:8000;
    }
  }
}

Tenga en cuenta que estamos utilizando hosts virtuales para enviar solicitudes de aplicaciones a un lugar y solicitudes de autenticación a otro. Una vez más, necesitamos transmitir los secretos a la VM. Y nuevamente, solo voy a copiar y pegar usando vi en la VM. Hasta ahora solo tenemos tres archivos secretos que deben copiarse y todos son archivos de texto que no cambian mucho, por lo que esto no parece una gran carga.

Abra una terminal SSH en su VM y ejecute vi config.yml. Luego, puede copiar el contenido de su ../config.yml local y pegarlo en el archivo de la VM. Luego, cd al directorio phpappprod y ejecute  docker-compose up. Ahora su aplicación debería estar activa en Internet, pero detrás de un inicio de sesión.

Si navega a su aplicación recién protegida, es posible que no tenga que iniciar sesión. Esto se debe a que es posible que aún esté conectado a Okta desde su sesión de configuración. Todas las aplicaciones, incluida Okta, serán de inicio de sesión único. Puede confirmar que Okta le permitió ingresar con las herramientas de desarrollo en Chrome.

Image for post

Hay tres solicitudes adicionales con estado 302, que lo redireccionan a la siguiente etapa. Además, almacenará una cookie para su nueva aplicación, por lo que solo debe realizarse el primer paso. La primera solicitud tarda aproximadamente un cuarto de segundo en ejecutarse, ya que está ubicada junto a Nginx y su aplicación; el retraso debería ser apenas perceptible. En configuraciones más complicadas, donde la redirección debe ir a Internet exterior, puede llevar un poco más de tiempo (pero ciertamente no tanto como para tener que escribir su contraseña una vez más).

Para ver qué sucede cuando se le solicita que inicie sesión, puede abrir una ventana de incógnito, buscar sus aplicaciones y se le debe solicitar que proporcione sus credenciales.

Image for post

Si desea incluir la pantalla de inicio de sesión en su aplicación para darle una marca única, Okta tiene formas de lograrlo, pero eso está más allá del alcance de este artículo.

Si desea dar diferentes alcances, la cookie que se pasa a su aplicación tiene un JWT que puede abrir para encontrar el nombre de usuario y los roles, de modo que pueda agregar una autorización basada en el nombre de usuario o el rol. Entonces, por ejemplo, puede permitir que cualquiera vea la lista, pero solo las personas en ciertos roles para agregarla.

Voy a dejarlo por ahora; la aplicación está protegida de forma segura por Okta, Nginx y Cloudflare, por lo que me complace dejarla ejecutándose así. Tenga en cuenta que para poder agregar este nivel de seguridad, no tuve que cambiar la aplicación principal en absoluto. De hecho, no importa que la aplicación sea PHP, podría ser cualquier lenguaje de expresión. Pero dado que esta es una serie sobre PHP moderno, utilicé la imagen de la aplicación PHP desarrollada anteriormente como ejemplo. Espero haberle podido ayudar a implementar sus aplicaciones en Internet con cierta sensación de seguridad. Si necesita más ayuda, el sitio web del desarrollador de Okta tiene explicaciones detalladas sobre cómo trabajar con el kit de herramientas de Okta en la mayoría de los lenguajes de expresión.

Todos los scripts (excepto los secretos) están contenidos en este repositorio:

 

https://github.com/rkamradt/phpappprod/tree/v0.2

 


Artículos anteriores:

  1. PHP moderno (Parte 1)
  2. Nginx como PHP moderno (Parte 2)

Recent Post