Skip to content

Commit b667be5

Browse files
feat(database): Added sops encryption for google cloud storage commit timestamp (#920)
Signed-off-by: Akhil Repala <[email protected]> Signed-off-by: Chris Gianelloni <[email protected]> Co-authored-by: Chris Gianelloni <[email protected]>
1 parent 69979ac commit b667be5

File tree

4 files changed

+365
-9
lines changed

4 files changed

+365
-9
lines changed

database/plugin/blob/gcs/commit_timestamp.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"context"
1919
"io"
2020
"math/big"
21+
22+
dingosops "github.com/blinklabs-io/dingo/database/sops"
2123
)
2224

2325
const commitTimestampBlobKey = "metadata_commit_timestamp"
@@ -29,18 +31,33 @@ func (b *BlobStoreGCS) GetCommitTimestamp(ctx context.Context) (int64, error) {
2931
return 0, err
3032
}
3133
defer r.Close()
32-
data, err := io.ReadAll(r)
34+
35+
ciphertext, err := io.ReadAll(r)
3336
if err != nil {
34-
b.logger.Errorf("failed to read data from object: %v", err)
37+
b.logger.Errorf("failed to read commit timestamp object: %v", err)
3538
return 0, err
3639
}
37-
return new(big.Int).SetBytes(data).Int64(), nil
40+
41+
plaintext, err := dingosops.Decrypt(ciphertext)
42+
if err != nil {
43+
b.logger.Errorf("failed to decrypt commit timestamp: %v", err)
44+
return 0, err
45+
}
46+
47+
return new(big.Int).SetBytes(plaintext).Int64(), nil
3848
}
3949

4050
func (b *BlobStoreGCS) SetCommitTimestamp(ctx context.Context, timestamp int64) error {
41-
w := b.bucket.Object(commitTimestampBlobKey).NewWriter(ctx)
42-
_, err := w.Write(new(big.Int).SetInt64(timestamp).Bytes())
51+
raw := new(big.Int).SetInt64(timestamp).Bytes()
52+
53+
ciphertext, err := dingosops.Encrypt(raw)
4354
if err != nil {
55+
b.logger.Errorf("failed to encrypt commit timestamp: %v", err)
56+
return err
57+
}
58+
59+
w := b.bucket.Object(commitTimestampBlobKey).NewWriter(ctx)
60+
if _, err := w.Write(ciphertext); err != nil {
4461
_ = w.Close()
4562
b.logger.Errorf("failed to write commit timestamp: %v", err)
4663
return err

database/sops/sops.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright 2025 Blink Labs Software
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package sops
16+
17+
import (
18+
"errors"
19+
"fmt"
20+
"os"
21+
22+
sopsapi "github.com/getsops/sops/v3"
23+
"github.com/getsops/sops/v3/aes"
24+
scommon "github.com/getsops/sops/v3/cmd/sops/common"
25+
"github.com/getsops/sops/v3/decrypt"
26+
"github.com/getsops/sops/v3/gcpkms"
27+
skeys "github.com/getsops/sops/v3/keys"
28+
jsonstore "github.com/getsops/sops/v3/stores/json"
29+
"github.com/getsops/sops/v3/version"
30+
)
31+
32+
func Decrypt(data []byte) ([]byte, error) {
33+
ret, err := decrypt.Data(data, "json")
34+
if err != nil {
35+
return nil, err
36+
}
37+
return ret, nil
38+
}
39+
40+
func Encrypt(data []byte) ([]byte, error) {
41+
input := &jsonstore.Store{}
42+
output := &jsonstore.Store{}
43+
44+
// prevent double encryption
45+
branches, err := input.LoadPlainFile(data)
46+
if err != nil {
47+
return nil, fmt.Errorf("error loading data: %w", err)
48+
}
49+
for _, branch := range branches {
50+
for _, b := range branch {
51+
if b.Key == "sops" {
52+
return nil, errors.New("already encrypted")
53+
}
54+
}
55+
}
56+
57+
// create tree and encrypt
58+
tree := sopsapi.Tree{Branches: branches}
59+
60+
// Configure Google KMS from env to encrypt
61+
rid := os.Getenv("DINGO_GCP_KMS_RESOURCE_ID")
62+
if rid == "" {
63+
return nil, errors.New("DINGO_GCP_KMS_RESOURCE_ID not set: SOPS requires at least one master key to encrypt")
64+
}
65+
keys := []skeys.MasterKey{}
66+
for _, k := range gcpkms.MasterKeysFromResourceIDString(rid) {
67+
keys = append(keys, k)
68+
}
69+
tree.Metadata = sopsapi.Metadata{
70+
KeyGroups: []sopsapi.KeyGroup{keys},
71+
Version: version.Version,
72+
}
73+
74+
dataKey, errs := tree.GenerateDataKey()
75+
if len(errs) > 0 {
76+
return nil, fmt.Errorf("failed generating data key: %v", errs)
77+
}
78+
if err := scommon.EncryptTree(scommon.EncryptTreeOpts{
79+
DataKey: dataKey,
80+
Tree: &tree,
81+
Cipher: aes.NewCipher(),
82+
}); err != nil {
83+
return nil, fmt.Errorf("failed encrypt: %w", err)
84+
}
85+
86+
encrypted, err := output.EmitEncryptedFile(tree)
87+
if err != nil {
88+
return nil, fmt.Errorf("failed output: %w", err)
89+
}
90+
return encrypted, nil
91+
}

go.mod

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/blinklabs-io/ouroboros-mock v0.3.8
1414
github.com/blinklabs-io/plutigo v0.0.12
1515
github.com/dgraph-io/badger/v4 v4.8.0
16+
github.com/getsops/sops/v3 v3.10.2
1617
github.com/glebarez/sqlite v1.11.0
1718
github.com/kelseyhightower/envconfig v1.4.0
1819
github.com/prometheus/client_golang v1.23.2
@@ -41,45 +42,95 @@ require (
4142
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
4243
cloud.google.com/go/compute/metadata v0.8.0 // indirect
4344
cloud.google.com/go/iam v1.5.2 // indirect
45+
cloud.google.com/go/kms v1.22.0 // indirect
46+
cloud.google.com/go/longrunning v0.6.7 // indirect
4447
cloud.google.com/go/monitoring v1.24.2 // indirect
48+
filippo.io/age v1.2.1 // indirect
4549
filippo.io/edwards25519 v1.1.0 // indirect
50+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
51+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 // indirect
52+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
53+
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 // indirect
54+
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect
55+
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
4656
github.com/ClickHouse/ch-go v0.61.5 // indirect
4757
github.com/ClickHouse/clickhouse-go/v2 v2.30.0 // indirect
4858
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect
4959
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
5060
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
61+
github.com/ProtonMail/go-crypto v1.2.0 // indirect
5162
github.com/andybalholm/brotli v1.1.1 // indirect
63+
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
64+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
65+
github.com/aws/aws-sdk-go-v2/config v1.29.14 // indirect
66+
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect
67+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
68+
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.72 // indirect
69+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
70+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
71+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
72+
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect
73+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
74+
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 // indirect
75+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
76+
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
77+
github.com/aws/aws-sdk-go-v2/service/kms v1.38.3 // indirect
78+
github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2 // indirect
79+
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
80+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
81+
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
82+
github.com/aws/smithy-go v1.22.3 // indirect
5283
github.com/beorn7/perks v1.0.1 // indirect
5384
github.com/bits-and-blooms/bitset v1.20.0 // indirect
85+
github.com/blang/semver v3.5.1+incompatible // indirect
5486
github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect
5587
github.com/btcsuite/btcd/btcutil v1.1.6 // indirect
5688
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
89+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
5790
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
5891
github.com/cespare/xxhash/v2 v2.3.0 // indirect
92+
github.com/cloudflare/circl v1.6.0 // indirect
5993
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
6094
github.com/consensys/gnark-crypto v0.19.0 // indirect
95+
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
6196
github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
6297
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
6398
github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect
6499
github.com/dustin/go-humanize v1.0.1 // indirect
65100
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
66101
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
102+
github.com/fatih/color v1.18.0 // indirect
67103
github.com/felixge/httpsnoop v1.0.4 // indirect
68104
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
105+
github.com/getsops/gopgagent v0.0.0-20241224165529-7044f28e491e // indirect
69106
github.com/glebarez/go-sqlite v1.21.2 // indirect
70107
github.com/go-faster/city v1.0.1 // indirect
71108
github.com/go-faster/errors v0.7.1 // indirect
72109
github.com/go-jose/go-jose/v4 v4.1.1 // indirect
73110
github.com/go-logr/logr v1.4.3 // indirect
74111
github.com/go-logr/stdr v1.2.2 // indirect
75112
github.com/go-sql-driver/mysql v1.7.0 // indirect
113+
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
76114
github.com/google/flatbuffers v25.2.10+incompatible // indirect
115+
github.com/google/go-cmp v0.7.0 // indirect
77116
github.com/google/s2a-go v0.1.9 // indirect
117+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
78118
github.com/google/uuid v1.6.0 // indirect
79119
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
80120
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
121+
github.com/goware/prefixer v0.0.0-20160118172347-395022866408 // indirect
81122
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
123+
github.com/hashicorp/errwrap v1.1.0 // indirect
124+
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
125+
github.com/hashicorp/go-multierror v1.1.1 // indirect
126+
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
127+
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
128+
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect
129+
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
130+
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
82131
github.com/hashicorp/go-version v1.6.0 // indirect
132+
github.com/hashicorp/hcl v1.0.0 // indirect
133+
github.com/hashicorp/vault/api v1.16.0 // indirect
83134
github.com/inconshreveable/mousetrap v1.1.0 // indirect
84135
github.com/jackc/pgpassfile v1.0.0 // indirect
85136
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
@@ -89,20 +140,31 @@ require (
89140
github.com/jinzhu/inflection v1.0.0 // indirect
90141
github.com/jinzhu/now v1.1.5 // indirect
91142
github.com/klauspost/compress v1.18.0 // indirect
92-
github.com/mattn/go-isatty v0.0.17 // indirect
143+
github.com/kylelemons/godebug v1.1.0 // indirect
144+
github.com/lib/pq v1.10.9 // indirect
145+
github.com/mattn/go-colorable v0.1.14 // indirect
146+
github.com/mattn/go-isatty v0.0.20 // indirect
147+
github.com/mitchellh/go-homedir v1.1.0 // indirect
148+
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
149+
github.com/mitchellh/mapstructure v1.5.0 // indirect
93150
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
94151
github.com/paulmach/orb v0.11.1 // indirect
95152
github.com/pierrec/lz4/v4 v4.1.21 // indirect
153+
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
96154
github.com/pkg/errors v0.9.1 // indirect
97155
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
98156
github.com/prometheus/client_model v0.6.2 // indirect
99157
github.com/prometheus/common v0.66.1 // indirect
100158
github.com/prometheus/procfs v0.16.1 // indirect
101159
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
160+
github.com/russross/blackfriday/v2 v2.1.0 // indirect
161+
github.com/ryanuber/go-glob v1.0.0 // indirect
102162
github.com/segmentio/asm v1.2.0 // indirect
103163
github.com/shopspring/decimal v1.4.0 // indirect
164+
github.com/sirupsen/logrus v1.9.3 // indirect
104165
github.com/spf13/pflag v1.0.9 // indirect
105166
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
167+
github.com/urfave/cli v1.22.16 // indirect
106168
github.com/x448/float16 v0.8.4 // indirect
107169
github.com/zeebo/errs v1.4.0 // indirect
108170
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
@@ -118,6 +180,7 @@ require (
118180
golang.org/x/crypto v0.42.0 // indirect
119181
golang.org/x/oauth2 v0.30.0 // indirect
120182
golang.org/x/sync v0.17.0 // indirect
183+
golang.org/x/term v0.35.0 // indirect
121184
golang.org/x/text v0.29.0 // indirect
122185
golang.org/x/time v0.12.0 // indirect
123186
google.golang.org/api v0.247.0 // indirect
@@ -126,6 +189,7 @@ require (
126189
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
127190
google.golang.org/grpc v1.75.0 // indirect
128191
google.golang.org/protobuf v1.36.8 // indirect
192+
gopkg.in/ini.v1 v1.67.0 // indirect
129193
gorm.io/driver/clickhouse v0.7.0 // indirect
130194
gorm.io/driver/mysql v1.5.7 // indirect
131195
gorm.io/driver/postgres v1.5.11 // indirect

0 commit comments

Comments
 (0)