Saltar al contenido principal

Proveedor Google Cloud Storage

Vali-Blob.GCP proporciona integración con Google Cloud Storage (GCS). Soporta cuentas de servicio con archivo JSON, credenciales inline en variables de entorno, y Application Default Credentials (ADC) para Cloud Run, GKE y Compute Engine.

Instalación

dotnet add package Vali-Blob.GCP

GCPStorageOptions

public class GCPStorageOptions
{
public required string ProjectId { get; set; }
public required string BucketName { get; set; }
public string? JsonCredentials { get; set; } // JSON inline de cuenta de servicio
public string? JsonCredentialsPath { get; set; } // Ruta al archivo .json de credenciales
public int TimeoutSeconds { get; set; } = 300;
}

Tabla de opciones

OpciónPor defectoDescripción
ProjectIdID del proyecto en GCP. Requerido.
BucketNameNombre del bucket. Requerido.
JsonCredentialsnullContenido JSON de la cuenta de servicio (inline).
JsonCredentialsPathnullRuta al archivo .json de credenciales.
TimeoutSeconds300Timeout para operaciones de almacenamiento.

Si JsonCredentials y JsonCredentialsPath son null, el proveedor usa Application Default Credentials automáticamente.

Configuración con archivo de credenciales

# Crear cuenta de servicio
gcloud iam service-accounts create valiblob-sa \
--display-name="Vali-Blob Storage Service Account" \
--project=mi-proyecto

# Asignar rol de administrador de objetos
gcloud projects add-iam-policy-binding mi-proyecto \
--member="serviceAccount:valiblob-sa@mi-proyecto.iam.gserviceaccount.com" \
--role="roles/storage.objectAdmin"

# Descargar archivo de credenciales
gcloud iam service-accounts keys create ./credenciales-gcs.json \
--iam-account=valiblob-sa@mi-proyecto.iam.gserviceaccount.com
builder.Services
.AddVali-Blob(o => o.DefaultProvider = "gcs")
.AddProvider<GCPStorageProvider>("gcs", opts =>
{
opts.ProjectId = builder.Configuration["GCP:ProjectId"]!;
opts.BucketName = builder.Configuration["GCP:BucketName"]!;
opts.JsonCredentialsPath = builder.Configuration["GCP:CredentialsPath"];
});

Configuración con credenciales como variable de entorno

# Guardar el contenido del JSON en una variable de entorno o secreto
export GCP__CredentialsJson="$(cat credenciales-gcs.json)"
builder.Services
.AddVali-Blob(o => o.DefaultProvider = "gcs")
.AddProvider<GCPStorageProvider>("gcs", opts =>
{
opts.ProjectId = builder.Configuration["GCP:ProjectId"]!;
opts.BucketName = builder.Configuration["GCP:BucketName"]!;
opts.JsonCredentials = builder.Configuration["GCP:CredentialsJson"];
});

Configuración con Application Default Credentials (Cloud Run, GKE, GCE)

En entornos gestionados de GCP, no se necesitan credenciales explícitas. El SDK detecta automáticamente el contexto:

builder.Services
.AddVali-Blob(o => o.DefaultProvider = "gcs")
.AddProvider<GCPStorageProvider>("gcs", opts =>
{
opts.ProjectId = "mi-proyecto-12345";
opts.BucketName = "mi-bucket-produccion";
// Sin JsonCredentials ni JsonCredentialsPath → ADC automático
});

Roles IAM requeridos

RolPermisosCuándo usar
roles/storage.objectAdminCRUD completo de objetosAplicaciones con lectura y escritura
roles/storage.objectViewerSolo lecturaServicios de solo lectura
roles/storage.objectCreatorSolo creaciónServicios de ingesta de datos
# Asignar rol al bucket específico (preferible a nivel de proyecto)
gcloud storage buckets add-iam-policy-binding gs://mi-bucket \
--member="serviceAccount:valiblob-sa@mi-proyecto.iam.gserviceaccount.com" \
--role="roles/storage.objectAdmin"

URLs firmadas (Signed URLs)

app.MapGet("/api/archivos/{*ruta}/enlace-temporal", async (
string ruta,
IStorageProvider storage,
CancellationToken ct) =>
{
if (storage is not IPresignedUrlProvider presigned)
return Results.StatusCode(501);

var resultado = await presigned.GetPresignedDownloadUrlAsync(
path: Uri.UnescapeDataString(ruta),
expiry: TimeSpan.FromMinutes(30),
ct);

return resultado.IsSuccess
? Results.Ok(new
{
url = resultado.Value,
expiraEn = DateTime.UtcNow.AddMinutes(30)
})
: Results.NotFound();
}).RequireAuthorization();

Crear y configurar el bucket

# Crear bucket con acceso uniforme (recomendado)
gcloud storage buckets create gs://mi-bucket \
--project=mi-proyecto \
--location=southamerica-east1 \
--uniform-bucket-level-access

# Configurar CORS para subidas directas desde el navegador
cat > cors-config.json << 'EOF'
[{
"origin": ["https://mi-app.com", "http://localhost:3000"],
"method": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"responseHeader": ["Content-Type", "ETag"],
"maxAgeSeconds": 3600
}]
EOF

gcloud storage buckets update gs://mi-bucket --cors-file=cors-config.json

Configuración completa en producción

{
"GCP": {
"ProjectId": "mi-proyecto-12345",
"BucketName": "mi-app-produccion",
"CredentialsPath": "/run/secrets/gcp-credentials.json"
}
}
var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddVali-Blob(o => o.DefaultProvider = "gcs")
.AddProvider<GCPStorageProvider>("gcs", opts =>
{
opts.ProjectId = builder.Configuration["GCP:ProjectId"]!;
opts.BucketName = builder.Configuration["GCP:BucketName"]!;

var credPath = builder.Configuration["GCP:CredentialsPath"];
if (!string.IsNullOrEmpty(credPath) && File.Exists(credPath))
opts.JsonCredentialsPath = credPath;
// Si no existe el archivo → usa ADC (Cloud Run, GKE, etc.)
})
.WithPipeline(p => p
.UseValidation(v =>
{
v.MaxFileSizeBytes = 5_000_000_000L; // 5 GB
v.BlockedExtensions = [".exe", ".bat", ".sh"];
})
.UseContentTypeDetection()
.UseConflictResolution(ConflictResolution.ReplaceExisting)
);

Regiones de GCP disponibles (selección)

RegiónIdentificadorZona geográfica
São Paulo, Brasilsouthamerica-east1América del Sur
Santiago, Chilesouthamerica-west1América del Sur
Iowa, EEUUus-central1Norteamérica
Virginia, EEUUus-east4Norteamérica
Bélgicaeurope-west1Europa
Tokio, Japónasia-northeast1Asia-Pacífico
Sídney, Australiaaustralia-southeast1Asia-Pacífico
Consejo

En Cloud Run y GKE, usa Workload Identity en lugar de archivos de credenciales en contenedores. Workload Identity vincula una cuenta de servicio de Kubernetes con una cuenta de servicio de GCP, eliminando completamente la necesidad de archivos .json en los pods.

Advertencia

Los archivos JSON de cuentas de servicio son credenciales permanentes con acceso completo a los recursos asignados. Almacénalos en Google Secret Manager, Kubernetes Secrets o tu gestor de secretos preferido. Nunca los incluyas en imágenes de Docker ni en repositorios de código.