¿Cómo desplegar recursos estáticos de una aplicación web usando un bucket privado?
Desplegar recursos estáticos [css, archivos javascript o imágenes] en el servicio de Almacenamiento de Google Cloud [referenciado como GCS por sus siglas en Inglés], que deben ser accedidos a través de internet ha representado un desafío para los ingenieros de infraestructura que requieren que los Buckets sean privados. Como se describe en la Implementación de Referencia, para que los Buckets puedan ser accedidos a través de un Balanceador de Carga Global Externo [ELB], deben configurarse como recursos públicos, lo que supone un riesgo para las organizaciones cuyas cargas de trabajo incluyen datos sensibles o privados, que no pueden exponerse directamente a internet. Y, aunque la solución alterna basada en URLs Firmadas funciona bien en la mayoría de los casos, esta requiere cambios en el lado del cliente, lo que también representa un desafío cuando las aplicaciones están sujetas al cumplimiento de reglamentaciones asociadas al negocio.
En septiembre de este año, el servicio de Red de Distribución de Contenido [CDN] agregó una nueva característica que permite autenticación de origen privado, lo que podría resolver el desafío descrito en el párrafo anterior. Sin embargo, la solución no es tan trivial, desde que la arquitectura de referencia incluye el aprovisionamiento de un Grupo de Extremo de Red [NEG], un servicio que aunque solo está recomendado para entregar cargas de trabajo basadas en grupos de instancias de VM, sin servidores o alojadas en contenedores, también puede usarse en Buckets.
Considerando los requerimientos y desafíos que esta última solución impone, este artículo ilustra la arquitectura de referencia y explica cómo puede usarse un NEG para acceder a un Bucket privado desde un ELB, haciendo uso de la funcionalidad incluida en CDN. A continuación se presenta la arquitectura de referencia y se describen los pasos requeridos en la Consola Gráfica y en la Línea de Comandos de Google Cloud:
Arquitectura de Referencia
Paso 1.
Autenticarse en la consola que se usará para la implementación.
Consola Gráfica a través de la URL https://cloud.google.com
Consola de Línea de Comandos
gcloud auth login
Paso 2.
Crear las variables de ambiente requeridas en la consola de línea de comandos [ignorar este paso si la configuración se realizará a través de la consola gráfica].
Consola de Línea de Comandos
export PROJECT_ID=[Copiar el ID del proyecto] \
export BUCKET_LOCATION=[Copiar el path local con los assets] \
export BUCKET_NAME=[Asignar un nombre para el Bucket] \
export SA_NAME=[Asignar un nombre para la Cuenta de Servicio] \
export NEG_NAME=[Asignar un nombre para el Network Endpoint Group] \
export LB_NAME=[Asignar un nombre para el Balanceador] \
export FRONTEND_NAME=[Asignar un nombre para el Front del LB] \
export BACKEND_NAME=[Asignar un nombre para el Back del LB] \
export FILE_NAME=[Asignar un nombre al archivo YAML del Backend] \
export IP_ADDRESS=[Asignar un nombre para la IP externa del LB]
Paso 3.
Crear el Bucket y asegurarse de que sea privado.
- Ir al servicio de Almacenamiento de Google Cloud.
- Asignar un nombre para el Bucket.
- Seleccionar las opciones:
- Aplicar la Prevención de Acceso Público a este Bucket.
- Uniforme en el panel de Control de Acceso a los Objetos.
Consola Gráfica
Consola de Línea de Comandos
gcloud storage buckets create gs://${BUCKET_NAME} \
- uniform-bucket-level-access
Paso 4.
Cargar el contenido estático al Bucket desde una máquina local.
- Ir al servicio de Almacenamiento de Google Cloud.
- Hacer clic en Subir Archivos o Subir Carpetas.
Consola Gráfica
Consola de Línea de Comandos
gsutil cp ${BUCKET_LOCATION} gs://${BUCKET_NAME}
Paso 5.
Crear una Cuenta de Servicio [SA] que será usada por el ELB para acceder al Bucket a través del NEG.
- Ir al servicio Cuenta de Servicios.
- Asignar un nombre para la SA.
- Dejar las otras opciones con los valores por defecto.
Consola Gráfica
Consola de Línea de Comandos
gcloud iam service-accounts create ${SA_NAME} - display-name=${SA_NAME}
Paso 6.
Asignar permisos para que la SA pueda acceder al Bucket.
- Ir al panel de edición del Bucket.
- Hacer clic en la sección Permisos del panel superior.
- Hacer clic en la opción Otorgar Acceso del panel inferior.
- Ingresar el nombre de la SA creada en el paso anterior.
- Seleccionar el rol Visualizador de Objetos de Storage.
Consola Gráfica
Consola de Línea de Comandos
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
- member=serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \
- role=roles/storage.viewer
Paso 6.
Crear las llaves HMAC que serán usadas por el servicio del Backend para acceder al Bucket.
- Ir al Servicio de Almacenamiento de Google Cloud:
- Hacer clic en la sección Configuración del servicio de Almacenamiento.
- Hacer clic en el panel Interoperabilidad de la sección Configuración.
- Hacer clic en el botón Crear Clave de Cuenta de Servicio.
- Seleccionar la SA creada en uno de los pasos anteriores.
- Tomar nota de la Clave de Acceso y el Secreto generados porque se requieren más adelante y como indica el mensaje de advertencia no se pueden recuperar después de que se cierra la ventana.
Consola Gráfica
Consola de Línea de Comandos
gcloud storage hmac create ${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com
Paso 7.
Crear un NEG (Global, Regional) con punto extremo en el Bucket.
- Ir al servicio Grupo Extremo de Red.
- Hacer clic en Crear Grupo Extremo de Red.
- Seleccionar NEG de Internet (Global, Regional) en la opción Tipo de Grupo de Extremo de Red.
- Seleccionar Nombre y Puerto de Dominio Completamente Calificados en la opción Agregar Tipo de Extremo.
- Ingresar la URL [Nombre Bucket].storage.googleapis.com en la opción Nombre de Dominio Completamente Calificado.
- Seleccionar Predeterminada en la opción Tipo de Puerto.
- Tener en cuenta que se usará Virtual Hosted-Style Cloud Storage XML API y que será agregado como un NEG de Internet, más información aquí.
Consola Gráfica
Consola de Línea de Comandos
gcloud compute network-endpoint-groups create ${NEG_NAME} \
- network-endpoint-type=internet-fqdn-port \
- global
gcloud compute network-endpoint-groups update ${NEG_NAME} \
- add-endpoint="fqdn=${BUCKET_NAME}.storage.googleapis.com,port=443"
Paso 8.
Crear el Backend para el Balanceador de Carga, seleccionar el NEG creado en uno de los pasos anteriores y habilitar el CDN como se describe a continuación.
- Ir al servicio Balanceo de Cargas.
- Hacer clic en la sección Crear Servicio de Backend.
- Hacer clic en el panel Backends.
- Seleccionar Servicio Backend Global.
- Asignar un nombre para el Servicio Backend.
- Seleccionar el protocolo HTTP o HTTPS si tiene un dominio y un certificado.
- Seleccionar la opción Grupo de Extremo de Red en la opción Tipo de Backend.
- Seleccionar el NEG creado anteriormente en la opción Grupo Extremo de Red.
- Habilitar el CDN seleccionando la opción Habilitar Cloud CDN.
- Seleccionar Contenido Estático en Caché en la opción Modo.
- Ingresar la URL [Nombre Bucket].storage.googleapis.com como encabezado en la opción Encabezados de Solicitud Personalizados.
- Hacer clic en Crear.
Consola Gráfica
Consola de Línea de Comandos
gcloud compute backend-services create ${BACKEND_NAME} \
- load-balancing-scheme=EXTERNAL \
- protocol=HTTP \
- global
Paso 9.
Crear el ELB Clásico Global.
- Ir al servicio Balanceo de Cargas.
- Hacer clic en la sección Balanceadores de Carga.
- Seleccionar Balanceador de Cargas de Aplicaciones (HTTP/S)
- Hacer clic en Iniciar Configuración.
- Seleccionar De Internet a mis VMs o Servicios sin Servidores.
- Seleccionar Balanceador de Carga de Aplicaciones Clásico.
Consola Gráfica
Consola de Línea de Comandos
gcloud compute url-maps create ${LB_NAME} \
- region=${REGION} \
- default-service=${BACKEND_NAME}
Paso 10.
En el mismo servicio de Balanceo de Cargas, crear el Servicio de Frontend.
- Asignar un nombre para el Servicio de Frontend.
- Crear una Dirección IP Estática Externa versión 4.
- Asignar un nombre para la Dirección IP.
Consola Gráfica
Consola de Línea de Comandos
gcloud compute target-http-proxies create ${FRONTEND_NAME} \
- url-map=${LB_NAME} \
- global
Paso 11.
En el mismo servicio de Balanceo de Cargas, seleccionar el Servicio de Backend creado en uno de los pasos anteriores.
Consola Gráfica
Paso 12.
Una vez creado el ELB, agregar las llaves HMAC a la definición del Servicio de Backend. Esta funcionalidad solo está disponible a través de la
Consola de Línea de Comandos
- Exportar la definición del Servicio de Backend a un archivo local.
- Agregar al archivo el fragmento de código SecuritySettings con los datos de la llave HMAC que se presenta más adelante.
- Remover del archivo las líneas que inician con:
Fingerprint
Id
usedBy
- Importar el archivo en la definición del Servicio de Backend.
gcloud beta compute backend-services describe ${BACKEND_NAME} \
- global > ${FILE_NAME}.yaml
securitySettings:
awsV4Authentication:
accessKeyId: [the access key from the HMAC]
accessKey: [the access key secret from the HMAC]
accessKeyVersion: Optional
originRegion: us-central-1
gcloud beta compute backend-services import ${BACKEND_NAME} - source ${FILE_NAME}.yaml - global
Paso Final
Eso es todo! Ya es posible probar el sitio desplegado en un navegador de internet.
Conclusión
Este artículo describió una solución al desafío que representa desplegar recursos estáticos en aplicaciones web que requieren sistemas de almacenamiento privados. La solución no es trivial porque la documentación de referencia hace uso de Buckets públicos. Para superar el desafío, la implementación aquí recomendada hizo uso de un Bucket privado [GCS], unGrupo de Extremo de Red [NEG], un Balanceador de Carga Global Externo [ELB] y una Red de Distribución de Contenido [CDN].