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:
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.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.Si está ejecutando en producción de Google App Engine, se utilizará la cuenta de servicio integrada asociada con la aplicación.
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.
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á solostorage.buckets.get
permiso y el mejor rol de IAM solo para este permiso esroles/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 rolroles/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”.