1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package api
17
18 import (
19 "context"
20 "crypto/sha256"
21 "crypto/tls"
22 "crypto/x509"
23 "encoding/hex"
24 "fmt"
25 "time"
26
27 "github.com/google/trillian"
28 "github.com/redis/go-redis/v9"
29 "github.com/spf13/viper"
30 "golang.org/x/exp/slices"
31 "google.golang.org/grpc"
32 "google.golang.org/grpc/credentials/insecure"
33
34 "github.com/sigstore/rekor/pkg/indexstorage"
35 "github.com/sigstore/rekor/pkg/log"
36 "github.com/sigstore/rekor/pkg/pubsub"
37 "github.com/sigstore/rekor/pkg/sharding"
38 "github.com/sigstore/rekor/pkg/signer"
39 "github.com/sigstore/rekor/pkg/storage"
40 "github.com/sigstore/rekor/pkg/trillianclient"
41 "github.com/sigstore/rekor/pkg/witness"
42 "github.com/sigstore/sigstore/pkg/cryptoutils"
43 "github.com/sigstore/sigstore/pkg/signature"
44 "github.com/sigstore/sigstore/pkg/signature/options"
45
46 _ "github.com/sigstore/rekor/pkg/pubsub/gcp"
47 )
48
49 func dial(ctx context.Context, rpcServer string) (*grpc.ClientConn, error) {
50 ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
51 defer cancel()
52
53
54 creds := insecure.NewCredentials()
55 conn, err := grpc.DialContext(ctx, rpcServer, grpc.WithTransportCredentials(creds))
56 if err != nil {
57 log.Logger.Fatalf("Failed to connect to RPC server:", err)
58 }
59 return conn, nil
60 }
61
62 type API struct {
63 logClient trillian.TrillianLogClient
64 logID int64
65 logRanges sharding.LogRanges
66 pubkey string
67 pubkeyHash string
68 signer signature.Signer
69
70 checkpointPublishCancel context.CancelFunc
71
72
73 newEntryPublisher pubsub.Publisher
74 }
75
76 func NewAPI(treeID uint) (*API, error) {
77 logRPCServer := fmt.Sprintf("%s:%d",
78 viper.GetString("trillian_log_server.address"),
79 viper.GetUint("trillian_log_server.port"))
80 ctx := context.Background()
81 tConn, err := dial(ctx, logRPCServer)
82 if err != nil {
83 return nil, fmt.Errorf("dial: %w", err)
84 }
85 logAdminClient := trillian.NewTrillianAdminClient(tConn)
86 logClient := trillian.NewTrillianLogClient(tConn)
87
88 shardingConfig := viper.GetString("trillian_log_server.sharding_config")
89 ranges, err := sharding.NewLogRanges(ctx, logClient, shardingConfig, treeID)
90 if err != nil {
91 return nil, fmt.Errorf("unable get sharding details from sharding config: %w", err)
92 }
93
94 tid := int64(treeID)
95 if tid == 0 {
96 log.Logger.Info("No tree ID specified, attempting to create a new tree")
97 t, err := trillianclient.CreateAndInitTree(ctx, logAdminClient, logClient)
98 if err != nil {
99 return nil, fmt.Errorf("create and init tree: %w", err)
100 }
101 tid = t.TreeId
102 }
103 log.Logger.Infof("Starting Rekor server with active tree %v", tid)
104 ranges.SetActive(tid)
105
106 rekorSigner, err := signer.New(ctx, viper.GetString("rekor_server.signer"),
107 viper.GetString("rekor_server.signer-passwd"))
108 if err != nil {
109 return nil, fmt.Errorf("getting new signer: %w", err)
110 }
111 pk, err := rekorSigner.PublicKey(options.WithContext(ctx))
112 if err != nil {
113 return nil, fmt.Errorf("getting public key: %w", err)
114 }
115 b, err := x509.MarshalPKIXPublicKey(pk)
116 if err != nil {
117 return nil, fmt.Errorf("marshalling public key: %w", err)
118 }
119 pubkeyHashBytes := sha256.Sum256(b)
120
121 pubkey := cryptoutils.PEMEncode(cryptoutils.PublicKeyPEMType, b)
122
123 var newEntryPublisher pubsub.Publisher
124 if p := viper.GetString("rekor_server.new_entry_publisher"); p != "" {
125 if !viper.GetBool("rekor_server.publish_events_protobuf") && !viper.GetBool("rekor_server.publish_events_json") {
126 return nil, fmt.Errorf("%q is configured but neither %q or %q are enabled", "new_entry_publisher", "publish_events_protobuf", "publish_events_json")
127 }
128 newEntryPublisher, err = pubsub.Get(ctx, p)
129 if err != nil {
130 return nil, fmt.Errorf("init event publisher: %w", err)
131 }
132 log.ContextLogger(ctx).Infof("Initialized new entry event publisher: %s", p)
133 }
134
135 return &API{
136
137 logClient: logClient,
138 logID: tid,
139 logRanges: ranges,
140
141 pubkey: string(pubkey),
142 pubkeyHash: hex.EncodeToString(pubkeyHashBytes[:]),
143 signer: rekorSigner,
144
145 newEntryPublisher: newEntryPublisher,
146 }, nil
147 }
148
149 var (
150 api *API
151 attestationStorageClient storage.AttestationStorage
152 indexStorageClient indexstorage.IndexStorage
153 redisClient *redis.Client
154 )
155
156 func ConfigureAPI(treeID uint) {
157 var err error
158
159 api, err = NewAPI(treeID)
160 if err != nil {
161 log.Logger.Panic(err)
162 }
163 if viper.GetBool("enable_retrieve_api") || viper.GetBool("enable_stable_checkpoint") ||
164 slices.Contains(viper.GetStringSlice("enabled_api_endpoints"), "searchIndex") {
165 indexStorageClient, err = indexstorage.NewIndexStorage(viper.GetString("search_index.storage_provider"))
166 if err != nil {
167 log.Logger.Panic(err)
168 }
169 }
170
171 if viper.GetBool("enable_attestation_storage") {
172 attestationStorageClient, err = storage.NewAttestationStorage()
173 if err != nil {
174 log.Logger.Panic(err)
175 }
176 }
177
178 if viper.GetBool("enable_stable_checkpoint") {
179 redisClient = NewRedisClient()
180 checkpointPublisher := witness.NewCheckpointPublisher(context.Background(), api.logClient, api.logRanges.ActiveTreeID(),
181 viper.GetString("rekor_server.hostname"), api.signer, redisClient, viper.GetUint("publish_frequency"), CheckpointPublishCount)
182
183
184 ctx, cancel := context.WithCancel(context.Background())
185 api.checkpointPublishCancel = cancel
186 checkpointPublisher.StartPublisher(ctx)
187 }
188 }
189
190 func NewRedisClient() *redis.Client {
191
192 opts := &redis.Options{
193 Addr: fmt.Sprintf("%v:%v", viper.GetString("redis_server.address"), viper.GetUint64("redis_server.port")),
194 Password: viper.GetString("redis_server.password"),
195 Network: "tcp",
196 DB: 0,
197 }
198
199
200 if viper.GetBool("redis_server.enable-tls") {
201 opts.TLSConfig = &tls.Config{
202 InsecureSkipVerify: viper.GetBool("redis_server.insecure-skip-verify"),
203 }
204 }
205
206 return redis.NewClient(opts)
207 }
208
209 func StopAPI() {
210 api.checkpointPublishCancel()
211
212 if api.newEntryPublisher != nil {
213 if err := api.newEntryPublisher.Close(); err != nil {
214 log.Logger.Errorf("shutting down newEntryPublisher: %v", err)
215 }
216 }
217
218 if indexStorageClient != nil {
219 if err := indexStorageClient.Shutdown(); err != nil {
220 log.Logger.Errorf("shutting down indexStorageClient: %v", err)
221 }
222 }
223 }
224
View as plain text