From 45bb24d1b9e4a7482a66f7e93486f59f20956e58 Mon Sep 17 00:00:00 2001 From: karreg Date: Wed, 15 Jul 2026 05:57:14 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=8F=20add=20managed=20identities?= =?UTF-8?q?=20to=20azblob=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- azblob/README.md | 10 +++++ azblob/exporter.go | 57 +++++++++++++++++++++------- azblob/exporter/schema.json | 59 ++++++++++++++++++++++++++++- azblob/go.mod | 5 +++ azblob/go.sum | 7 ++++ azblob/importer.go | 59 ++++++++++++++++++++++------- azblob/importer/schema.json | 59 ++++++++++++++++++++++++++++- azblob/storage.go | 74 ++++++++++++++++++++++++++++--------- azblob/storage/schema.json | 59 ++++++++++++++++++++++++++++- 9 files changed, 339 insertions(+), 50 deletions(-) diff --git a/azblob/README.md b/azblob/README.md index 43b4f5c7..02349627 100644 --- a/azblob/README.md +++ b/azblob/README.md @@ -29,12 +29,22 @@ The supported configuration options are: * `account_key`: Azure Storage account key * `endpoint`: custom endpoint (e.g. Azurite or non-standard Azure environments) * `no_auth`: disable authentication (useful for public containers or testing) +* `use_managed_identity`: enable Azure AD authentication through `DefaultAzureCredential` +* `managed_identity_client_id`: optional client ID for user-assigned managed identity At least one authentication method must be provided: * `connection_string` * OR `account_name` + `account_key` * OR `no_auth=true` with a valid `endpoint` +* OR `use_managed_identity=true` with: + * `account_name` (service URL inferred as `https://.blob.core.windows.net`) + * or `endpoint` + +Managed identity notes: + +* System-assigned identity: set `use_managed_identity=true`. +* User-assigned identity: set `use_managed_identity=true` and `managed_identity_client_id=`. --- diff --git a/azblob/exporter.go b/azblob/exporter.go index 813ba08d..d762de88 100644 --- a/azblob/exporter.go +++ b/azblob/exporter.go @@ -6,6 +6,7 @@ import ( "path" "strings" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/PlakarKorp/kloset/connectors" "github.com/PlakarKorp/kloset/connectors/exporter" @@ -21,28 +22,32 @@ type azblobExporter struct { path string endpoint string - accountName string - accountKey string - connectionString string - noAuth bool + accountName string + accountKey string + connectionString string + noAuth bool + useManagedIdentity bool + managedIdentityClientID string client *azblob.Client } func NewExporter(ctx context.Context, _ *connectors.Options, proto string, params map[string]string) (exporter.Exporter, error) { - container, prefix, endpoint, accountName, accountKey, connectionString, noAuth, err := parse(params, proto) + container, prefix, endpoint, accountName, accountKey, connectionString, noAuth, useManagedIdentity, managedIdentityClientID, err := parse(params, proto) if err != nil { return nil, err } exp := &azblobExporter{ - containerName: container, - path: prefix, - endpoint: endpoint, - accountName: accountName, - accountKey: accountKey, - connectionString: connectionString, - noAuth: noAuth, + containerName: container, + path: prefix, + endpoint: endpoint, + accountName: accountName, + accountKey: accountKey, + connectionString: connectionString, + noAuth: noAuth, + useManagedIdentity: useManagedIdentity, + managedIdentityClientID: managedIdentityClientID, } if err := exp.connect(ctx); err != nil { @@ -95,8 +100,34 @@ func (g *azblobExporter) connect(ctx context.Context) error { g.client = client return nil + case g.useManagedIdentity: + serviceURL := g.endpoint + if serviceURL == "" { + if g.accountName == "" { + return fmt.Errorf("managed identity requires endpoint or account_name") + } + serviceURL = fmt.Sprintf("https://%s.blob.core.windows.net", g.accountName) + } + + opts := &azidentity.ManagedIdentityCredentialOptions{} + if g.managedIdentityClientID != "" { + opts.ID = azidentity.ClientID(g.managedIdentityClientID) + } + + cred, err := azidentity.NewManagedIdentityCredential(opts) + if err != nil { + return err + } + + client, err := azblob.NewClient(strings.TrimRight(serviceURL, "/")+"/", cred, nil) + if err != nil { + return err + } + g.client = client + return nil + default: - return fmt.Errorf("missing credentials: provide connection_string, or account_name/account_key, or no_auth=true with endpoint") + return fmt.Errorf("missing credentials: provide connection_string, or account_name/account_key, or no_auth=true with endpoint, or use_managed_identity=true with endpoint or account_name") } } diff --git a/azblob/exporter/schema.json b/azblob/exporter/schema.json index a76fea0a..da56b281 100644 --- a/azblob/exporter/schema.json +++ b/azblob/exporter/schema.json @@ -37,6 +37,16 @@ "type": "boolean", "default": false, "description": "Disable authentication, useful for public blobs or specific emulator/test setups" + }, + "use_managed_identity": { + "type": "boolean", + "default": false, + "description": "Enable Azure AD authentication via DefaultAzureCredential (supports system-assigned and user-assigned managed identity)" + }, + "managed_identity_client_id": { + "type": "string", + "minLength": 1, + "description": "Optional client ID for user-assigned managed identity" } }, "oneOf": [ @@ -44,14 +54,28 @@ "required": [ "location", "connection_string" - ] + ], + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } }, { "required": [ "location", "account_name", "account_key" - ] + ], + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } }, { "required": [ @@ -63,6 +87,37 @@ "no_auth": { "const": true } + }, + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } + }, + { + "required": [ + "location", + "use_managed_identity", + "account_name" + ], + "properties": { + "use_managed_identity": { + "const": true + } + } + }, + { + "required": [ + "location", + "use_managed_identity", + "endpoint" + ], + "properties": { + "use_managed_identity": { + "const": true + } } } ] diff --git a/azblob/go.mod b/azblob/go.mod index 1db9773c..1bb65e5e 100644 --- a/azblob/go.mod +++ b/azblob/go.mod @@ -3,6 +3,7 @@ module github.com/PlakarKorp/integrations/azblob go 1.24.0 require ( + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 github.com/PlakarKorp/go-kloset-sdk v1.1.0-beta.1 github.com/PlakarKorp/kloset v1.1.0-beta.2 @@ -11,15 +12,19 @@ require ( require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect github.com/PlakarKorp/integration-grpc v1.1.0-beta.3 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect github.com/nickball/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5 // indirect github.com/pierrec/lz4/v4 v4.1.25 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/tink-crypto/tink-go/v2 v2.6.0 // indirect diff --git a/azblob/go.sum b/azblob/go.sum index f36ad05e..f358620d 100644 --- a/azblob/go.sum +++ b/azblob/go.sum @@ -2,12 +2,16 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16AP github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 h1:jWQK1GI+LeGGUKBADtcH2rRqPxYB1Ljwms5gFA2LqrM= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4/go.mod h1:8mwH4klAm9DUgR2EEHyEEAQlRDvLPyg5fQry3y+cDew= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= @@ -80,6 +84,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= +github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= @@ -156,6 +162,7 @@ golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= diff --git a/azblob/importer.go b/azblob/importer.go index 72aeaea2..2334834d 100644 --- a/azblob/importer.go +++ b/azblob/importer.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/PlakarKorp/kloset/connectors" "github.com/PlakarKorp/kloset/connectors/importer" @@ -25,29 +26,33 @@ type azblobImporter struct { base string endpoint string - accountName string - accountKey string - connectionString string - noAuth bool + accountName string + accountKey string + connectionString string + noAuth bool + useManagedIdentity bool + managedIdentityClientID string client *azblob.Client } func NewImporter(ctx context.Context, _ *connectors.Options, proto string, params map[string]string) (importer.Importer, error) { - container, prefix, endpoint, accountName, accountKey, connectionString, noAuth, err := parse(params, proto) + container, prefix, endpoint, accountName, accountKey, connectionString, noAuth, useManagedIdentity, managedIdentityClientID, err := parse(params, proto) if err != nil { return nil, err } imp := &azblobImporter{ - containerName: container, - path: prefix, - base: "/" + prefix, - endpoint: endpoint, - accountName: accountName, - accountKey: accountKey, - connectionString: connectionString, - noAuth: noAuth, + containerName: container, + path: prefix, + base: "/" + prefix, + endpoint: endpoint, + accountName: accountName, + accountKey: accountKey, + connectionString: connectionString, + noAuth: noAuth, + useManagedIdentity: useManagedIdentity, + managedIdentityClientID: managedIdentityClientID, } if err := imp.connect(ctx); err != nil { @@ -100,8 +105,34 @@ func (g *azblobImporter) connect(ctx context.Context) error { g.client = client return nil + case g.useManagedIdentity: + serviceURL := g.endpoint + if serviceURL == "" { + if g.accountName == "" { + return fmt.Errorf("managed identity requires endpoint or account_name") + } + serviceURL = fmt.Sprintf("https://%s.blob.core.windows.net", g.accountName) + } + + opts := &azidentity.ManagedIdentityCredentialOptions{} + if g.managedIdentityClientID != "" { + opts.ID = azidentity.ClientID(g.managedIdentityClientID) + } + + cred, err := azidentity.NewManagedIdentityCredential(opts) + if err != nil { + return err + } + + client, err := azblob.NewClient(strings.TrimRight(serviceURL, "/")+"/", cred, nil) + if err != nil { + return err + } + g.client = client + return nil + default: - return fmt.Errorf("missing credentials: provide connection_string, or account_name/account_key, or no_auth=true with endpoint") + return fmt.Errorf("missing credentials: provide connection_string, or account_name/account_key, or no_auth=true with endpoint, or use_managed_identity=true with endpoint or account_name") } } diff --git a/azblob/importer/schema.json b/azblob/importer/schema.json index 8d146c63..dc99b04d 100644 --- a/azblob/importer/schema.json +++ b/azblob/importer/schema.json @@ -37,6 +37,16 @@ "type": "boolean", "default": false, "description": "Disable authentication, useful for public blobs or specific emulator/test setups" + }, + "use_managed_identity": { + "type": "boolean", + "default": false, + "description": "Enable Azure AD authentication via DefaultAzureCredential (supports system-assigned and user-assigned managed identity)" + }, + "managed_identity_client_id": { + "type": "string", + "minLength": 1, + "description": "Optional client ID for user-assigned managed identity" } }, "oneOf": [ @@ -44,14 +54,28 @@ "required": [ "location", "connection_string" - ] + ], + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } }, { "required": [ "location", "account_name", "account_key" - ] + ], + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } }, { "required": [ @@ -63,6 +87,37 @@ "no_auth": { "const": true } + }, + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } + }, + { + "required": [ + "location", + "use_managed_identity", + "account_name" + ], + "properties": { + "use_managed_identity": { + "const": true + } + } + }, + { + "required": [ + "location", + "use_managed_identity", + "endpoint" + ], + "properties": { + "use_managed_identity": { + "const": true + } } } ] diff --git a/azblob/storage.go b/azblob/storage.go index 23235778..cf921665 100644 --- a/azblob/storage.go +++ b/azblob/storage.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" @@ -27,15 +28,17 @@ type azblobStore struct { path string endpoint string - accountName string - accountKey string - connectionString string - noAuth bool + accountName string + accountKey string + connectionString string + noAuth bool + useManagedIdentity bool + managedIdentityClientID string client *azblob.Client } -func parse(params map[string]string, proto string) (container, prefix, endpoint, accountName, accountKey, connectionString string, noAuth bool, err error) { +func parse(params map[string]string, proto string) (container, prefix, endpoint, accountName, accountKey, connectionString string, noAuth, useManagedIdentity bool, managedIdentityClientID string, err error) { for k, v := range params { switch k { case "connection_string": @@ -56,40 +59,51 @@ func parse(params map[string]string, proto string) (container, prefix, endpoint, case "no_auth": noAuth, err = strconv.ParseBool(v) if err != nil { - return "", "", "", "", "", "", false, fmt.Errorf("unknown value for no_auth %q: %w", v, err) + return "", "", "", "", "", "", false, false, "", fmt.Errorf("unknown value for no_auth %q: %w", v, err) } + case "use_managed_identity": + useManagedIdentity, err = strconv.ParseBool(v) + if err != nil { + return "", "", "", "", "", "", false, false, "", fmt.Errorf("unknown value for use_managed_identity %q: %w", v, err) + } + + case "managed_identity_client_id": + managedIdentityClientID = v + case "location": // azblob://container/prefix container, prefix, _ = strings.Cut(strings.TrimPrefix(v, proto+"://"), "/") prefix = strings.Trim(prefix, "/") default: - return "", "", "", "", "", "", false, fmt.Errorf("unknown option: %s", k) + return "", "", "", "", "", "", false, false, "", fmt.Errorf("unknown option: %s", k) } } if container == "" { - return "", "", "", "", "", "", false, fmt.Errorf("missing container in location") + return "", "", "", "", "", "", false, false, "", fmt.Errorf("missing container in location") } return } func NewStore(ctx context.Context, proto string, params map[string]string) (storage.Store, error) { - container, prefix, endpoint, accountName, accountKey, connectionString, noAuth, err := parse(params, proto) + container, prefix, endpoint, accountName, accountKey, connectionString, noAuth, useManagedIdentity, managedIdentityClientID, err := parse(params, proto) if err != nil { return nil, err } return &azblobStore{ - containerName: container, - path: prefix, - endpoint: endpoint, - accountName: accountName, - accountKey: accountKey, - connectionString: connectionString, - noAuth: noAuth, + containerName: container, + path: prefix, + endpoint: endpoint, + accountName: accountName, + accountKey: accountKey, + connectionString: connectionString, + noAuth: noAuth, + useManagedIdentity: useManagedIdentity, + managedIdentityClientID: managedIdentityClientID, }, nil } @@ -136,8 +150,34 @@ func (g *azblobStore) connect(ctx context.Context) error { g.client = client return nil + case g.useManagedIdentity: + serviceURL := g.endpoint + if serviceURL == "" { + if g.accountName == "" { + return fmt.Errorf("managed identity requires endpoint or account_name") + } + serviceURL = fmt.Sprintf("https://%s.blob.core.windows.net", g.accountName) + } + + opts := &azidentity.ManagedIdentityCredentialOptions{} + if g.managedIdentityClientID != "" { + opts.ID = azidentity.ClientID(g.managedIdentityClientID) + } + + cred, err := azidentity.NewManagedIdentityCredential(opts) + if err != nil { + return err + } + + client, err := azblob.NewClient(strings.TrimRight(serviceURL, "/")+"/", cred, nil) + if err != nil { + return err + } + g.client = client + return nil + default: - return fmt.Errorf("missing credentials: provide connection_string, or account_name/account_key, or no_auth=true with endpoint") + return fmt.Errorf("missing credentials: provide connection_string, or account_name/account_key, or no_auth=true with endpoint, or use_managed_identity=true with endpoint or account_name") } } diff --git a/azblob/storage/schema.json b/azblob/storage/schema.json index 7e973084..22ee7edc 100644 --- a/azblob/storage/schema.json +++ b/azblob/storage/schema.json @@ -37,6 +37,16 @@ "type": "boolean", "default": false, "description": "Disable authentication, useful for public blobs or specific emulator/test setups" + }, + "use_managed_identity": { + "type": "boolean", + "default": false, + "description": "Enable Azure AD authentication via DefaultAzureCredential (supports system-assigned and user-assigned managed identity)" + }, + "managed_identity_client_id": { + "type": "string", + "minLength": 1, + "description": "Optional client ID for user-assigned managed identity" } }, "oneOf": [ @@ -44,14 +54,28 @@ "required": [ "location", "connection_string" - ] + ], + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } }, { "required": [ "location", "account_name", "account_key" - ] + ], + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } }, { "required": [ @@ -63,6 +87,37 @@ "no_auth": { "const": true } + }, + "not": { + "properties": { + "use_managed_identity": { + "const": true + } + } + } + }, + { + "required": [ + "location", + "use_managed_identity", + "account_name" + ], + "properties": { + "use_managed_identity": { + "const": true + } + } + }, + { + "required": [ + "location", + "use_managed_identity", + "endpoint" + ], + "properties": { + "use_managed_identity": { + "const": true + } } } ] From d940a456f578ba08a97f749a9db09b38de5fc82c Mon Sep 17 00:00:00 2001 From: karreg Date: Wed, 15 Jul 2026 08:05:04 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=8D=EF=B8=8F=20improve=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- azblob/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azblob/README.md b/azblob/README.md index 02349627..9bcf73a8 100644 --- a/azblob/README.md +++ b/azblob/README.md @@ -51,6 +51,11 @@ Managed identity notes: ## Examples ```sh +# add a store +$ plakar add store azblob://container_name --connection-string "DefaultEndpointsProtocol=https;AccountName=account_name;AccountKey=account_key;EndpointSuffix=core.windows.net" +$ plakar add store azblob://container_name --account-name account_name --account-key account_key +$ plakar add store azblob://container_name --use-managed-identity=true account_name=account_name + # back up a container $ plakar at /tmp/store backup azblob://container_name From 36a81ecbd2144d267ab9d20eeae7d891dc6dfc2c Mon Sep 17 00:00:00 2001 From: karreg Date: Wed, 15 Jul 2026 08:05:20 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20add=20makefile=20ta?= =?UTF-8?q?rgets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- azblob/Makefile | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/azblob/Makefile b/azblob/Makefile index ef90fb3c..e8785537 100644 --- a/azblob/Makefile +++ b/azblob/Makefile @@ -1,6 +1,13 @@ -GO = go +GO=go EXT= +PLAKAR = plakar +VERSION = v1.1.0-beta.2 + +GOOS := $(shell go env GOOS) +GOARCH := $(shell go env GOARCH) +PTAR := azblob_$(VERSION)_$(GOOS)_$(GOARCH).ptar + all: build build: @@ -8,5 +15,17 @@ build: ${GO} build -v -o azblob-exporter${EXT} ./exporter ${GO} build -v -o azblob-storage${EXT} ./storage +package: build + rm -f $(PTAR) + $(PLAKAR) pkg create ./manifest.yaml $(VERSION) + +uninstall: + -$(PLAKAR) pkg rm azblob + +install: package + $(PLAKAR) pkg add ./$(PTAR) + +reinstall: uninstall install + clean: - rm -f azblob-importer azblob-exporter azblob-storage + rm -f azblob-importer azblob-exporter azblob-storage azblob_*.ptar