¿Cómo desplegar recursos estáticos de una aplicación web usando un bucket privado?

Yury Niño
google-cloud-hispanoamerica
8 min readJan 3, 2024

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

Figura 0. 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

Figura 1. Autenticación en la Consola Gráfica

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

Figura 2. Asignación de un nombre para el Bucket
Figura 3. Configuración para prevenir el acceso público al Bucket.
Figura 4. Confirmación de acceso privado al Bucket.

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

Figura 5. Carga de contenido al Bucket.

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

Figura 6. Creación de Cuenta de Servicio

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

Figura 7. Asignación de permisos para la SA sobre el Bucket.
Figura 8. Asignación del rol de lectura de objetos para la SA.

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

Figura 9. Creación de llaves HMAC.
Figura 10. Selección de la SA para la llave HMAC
Figura 11. Recuperación de Access Key y Secret de la llave HMAC

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

Figura 12. Creación de un NEG.
Figura 13. Creación de un NEG conectado al Bucket.

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

Figura 14. Creación del Backend para el ELB Clásico Global.
Figura 15. Selección de la opción Global para el Servicio de Backend.
Figura 16. Asignación de un nombre y selección del protocolo para el servicio de Backend.
Figura 17. Adición del NEG al Servicio de Backend.
Figura 18. Configuración del CDN en el Backend del ELB.
Figura 19. Configuración de un Encabezado para el CDN.

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

Figura 20. Creación del ELB Clásico Global.
Figura 21. Creación del ELB Clásico Global.
Figura 22. Creación del Balanceador de Carga.

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

Figura 23. Configuración del Frontend del ELB.
Figura 24. Reserva de una IP Externa para el ELB.

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

Figura 25. Adición del Servicio de Backend al ELB.
Figura 26. Finalización de creación del ELB.

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.

Figura 26. Prueba 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].

--

--

Yury Niño
google-cloud-hispanoamerica

Cloud Infrastructure Engineer @Google. Chaos Engineer Advocate. Loves building software applications, DevOps, Security and SRE