Saltar al contenido

Google Cloud Storage con una cuenta de servicio en Java: la persona que llama 403 no tiene acceso a storage.objects.list al depósito

Solución:

TL; DR – Si estás usando Application Default Credentials (que por cierto eres cuando lo haces StorageOptions.getDefaultInstance().getService();), y si necesita usar las credenciales de una cuenta de servicio, puede hacerlo sin cambiar tu código. Todo lo que necesita hacer es configurar el GOOGLE_APPLICATION_CREDENTIALS variable de entorno a la ruta completa del archivo json de su cuenta de servicio y ya está todo listo.

Versión más larga de la solución usando Application Default Credentials

  • Usa tu código original tal cual

    Storage storage = StorageOptions.getDefaultInstance().getService();
    Bucket b = storage.get( "mybucketname" );
    
  • Establecer la variable de entorno GOOGLE_APPLICATION_CREDENTIALS a la ruta completa de su archivo json que contiene las credenciales de la cuenta de servicio.

    export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account_credentials.json
    
  • Ejecute su aplicación Java una vez más para verificar que esté funcionando como se esperaba.

Solución alternativa que utiliza credenciales de cuenta de servicio codificadas de forma rígida

El ejemplo de código que publicó para inicializar ServiceAccountCredentials me parece válido a simple vista. Probé el siguiente fragmento de código y me está funcionando como se esperaba.

String SERVICE_ACCOUNT_JSON_PATH = "/path/to/service_account_credentials.json";

Storage storage =
    StorageOptions.newBuilder()
        .setCredentials(
            ServiceAccountCredentials.fromStream(
                new FileInputStream(SERVICE_ACCOUNT_JSON_PATH)))
        .build()
        .getService();
Bucket b = storage.get("mybucketname");

Al especificar una credencial de cuenta de servicio, el ID del proyecto se obtiene automáticamente de la información presente en el archivo json. Por lo tanto, no es necesario que vuelva a especificarlo. Sin embargo, no estoy del todo seguro si esto está relacionado con el problema que está observando.

Credenciales predeterminadas de la aplicación

Aquí está la documentación completa sobre Application Default Credentials explicando qué credenciales se obtienen en función de su entorno.

Cómo funcionan las credenciales predeterminadas de la aplicación

Puede obtener las credenciales predeterminadas de la aplicación haciendo una sola llamada a la biblioteca cliente. Las credenciales devueltas están determinadas por el entorno en el que se ejecuta el código. Las condiciones se verifican en el siguiente orden:

  1. La variable de entorno GOOGLE_APPLICATION_CREDENTIALS está chequeado. Si se especifica esta variable, debe apuntar a un archivo que defina las credenciales. La forma más sencilla de obtener una credencial para este propósito es crear una clave de cuenta de servicio en la Consola API de Google:

    una. Vaya a la página Credenciales de la consola API.

    B. En el menú desplegable del proyecto, seleccione su proyecto.

    C. En la página Credenciales, seleccione el menú desplegable Crear credenciales y luego seleccione Clave de cuenta de servicio.

    d.En el menú desplegable Cuenta de servicio, seleccione una cuenta de servicio existente o cree una nueva.

    mi. Para Tipo de clave, seleccione la opción de clave JSON, luego seleccione Crear. El archivo se descarga automáticamente a su computadora.

    F. Coloque el archivo * .json que acaba de descargar en un directorio de su elección. Este directorio debe ser privado (no puede permitir que nadie acceda a él), pero accesible para el código de su servidor web.

    gramo. Establecer la variable de entorno GOOGLE_APPLICATION_CREDENTIALS a la ruta del archivo JSON descargado.

  2. Si ha instalado el SDK de Google Cloud en su máquina y ha ejecutado el comando gcloud auth application-default login, su identidad se puede utilizar como un proxy para probar el código que llama a las API desde esa máquina.

  3. Si está ejecutando en producción de Google App Engine, se utilizará la cuenta de servicio integrada asociada con la aplicación.

  4. Si está ejecutando en la producción de Google Compute Engine, se utilizará la cuenta de servicio integrada asociada con la instancia de la máquina virtual.

  5. Si no se cumple ninguna de estas condiciones, se producirá un error.

Roles de IAM

Recomendaría repasar el IAM permissions y el IAM roles disponible para Cloud Storage. Estos proporcionan control a nivel de proyecto y de cubo. Además, puede usar LCA para controlar los permisos a nivel de objeto dentro del depósito.

  • Si su caso de uso implica simplemente invocar storage.get(bucketName). Esta operación requerirá solo storage.buckets.get permiso y el mejor rol de IAM solo para este permiso es roles/storage.legacyObjectReader.

  • Si también desea otorgar permisos a la cuenta de servicio para obtener (storage.objects.get) y lista (storage.objects.list) objetos individuales, luego también agregue el rol roles/storage.objectViewer a la cuenta de servicio.

Gracias a la larga explicación de @ Taxdude, entendí que mi código Java debería estar bien y comencé a buscar otras posibles razones del problema.

Una de las cosas adicionales que probé fueron los permisos establecidos para la cuenta de servicio, y allí encontré la solución; en realidad, fue inesperado.

Cuando se crea una cuenta de servicio, no se le deben otorgar permisos para leer desde Google Storage, porque entonces tendrá permisos de lectura para TODOS los depósitos, y es imposible cambiar eso (no estoy seguro de por qué), porque el sistema marca estos permisos como “heredado”.

Por lo tanto, debes:

  • Cree una cuenta de servicio “en blanco” sin permisos y
  • Configure los permisos desde la configuración del depósito

Para hacerlo:

  • Abra la consola web de Google Cloud
  • Abrir navegador de almacenamiento
  • Seleccione su cubo
  • Abre el PANEL DE INFORMACIÓN con Permisos
  • Agregue la cuenta de servicio con el Visor de objetos de almacenamiento permiso, pero también hay permisos denominados Lector de objetos heredados de almacenamiento y Lector de cubos de almacenamiento heredado

Debido a la palabra “Legacy”, pensé que no deberían usarse, se ven como algo guardado para compatibilidad con versiones anteriores. Y después de experimentar y agregar estos permisos “heredados”, de repente, el mismo código que estaba probando todo el tiempo comenzó a funcionar correctamente.

Todavía no estoy completamente seguro de cuál es el conjunto mínimo de permisos que debo asignar a una cuenta de servicio, pero al menos ahora funciona con los tres permisos de “lectura” en el depósito: dos “heredados” y uno “normal”.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *