-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
cluster_databases.go
143 lines (118 loc) · 3.99 KB
/
cluster_databases.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
Copyright 2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package clusters
import (
"context"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/defaults"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/client"
dbprofile "github.com/gravitational/teleport/lib/client/db"
libdefaults "github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/teleterm/api/uri"
"github.com/gravitational/teleport/lib/tlsca"
"github.com/gravitational/trace"
)
// Database describes database
type Database struct {
// URI is the database URI
URI uri.ResourceURI
types.Database
}
// GetDatabase returns a database
func (c *Cluster) GetDatabase(ctx context.Context, dbURI string) (*Database, error) {
dbs, err := c.GetDatabases(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
for _, db := range dbs {
if db.URI.String() == dbURI {
return &db, nil
}
}
return nil, trace.NotFound("database is not found: %v", dbURI)
}
// GetDatabases returns databases
func (c *Cluster) GetDatabases(ctx context.Context) ([]Database, error) {
proxyClient, err := c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
defer proxyClient.Close()
dbservers, err := proxyClient.FindDatabaseServersByFilters(ctx, proto.ListResourcesRequest{
Namespace: defaults.Namespace,
})
if err != nil {
return nil, trace.Wrap(err)
}
var dbs []types.Database
for _, server := range dbservers {
dbs = append(dbs, server.GetDatabase())
}
dbs = types.DeduplicateDatabases(dbs)
var responseDbs []Database
for _, db := range dbs {
responseDbs = append(responseDbs, Database{
URI: c.URI.AppendDB(db.GetName()),
Database: db,
})
}
return responseDbs, nil
}
// ReissueDBCerts issues new certificates for specific DB access
func (c *Cluster) ReissueDBCerts(ctx context.Context, user, dbName string, db types.Database) error {
// When generating certificate for MongoDB access, database username must
// be encoded into it. This is required to be able to tell which database
// user to authenticate the connection as.
if db.GetProtocol() == libdefaults.ProtocolMongoDB && user == "" {
return trace.BadParameter("please provide the database user name using --db-user flag")
}
err := c.clusterClient.ReissueUserCerts(ctx, client.CertCacheKeep, client.ReissueParams{
RouteToCluster: c.clusterClient.SiteName,
RouteToDatabase: proto.RouteToDatabase{
ServiceName: db.GetName(),
Protocol: db.GetProtocol(),
Username: user,
Database: dbName,
},
AccessRequests: c.status.ActiveRequests.AccessRequests,
})
if err != nil {
return trace.Wrap(err)
}
// Update the database-specific connection profile file.
err = dbprofile.Add(c.clusterClient, tlsca.RouteToDatabase{
ServiceName: db.GetName(),
Protocol: db.GetProtocol(),
Username: user,
Database: dbName,
}, c.status)
if err != nil {
return trace.Wrap(err)
}
return nil
}
// GetAllowedDatabaseUsers returns allowed users for the given database based on the role set.
func (c *Cluster) GetAllowedDatabaseUsers(ctx context.Context, dbURI string) ([]string, error) {
roleSet, err := services.FetchRoles(c.status.Roles, c.clusterClient, c.status.Traits)
if err != nil {
return nil, trace.Wrap(err)
}
db, err := c.GetDatabase(ctx, dbURI)
if err != nil {
return nil, trace.Wrap(err)
}
dbUsers := roleSet.EnumerateDatabaseUsers(db)
return dbUsers.Allowed(), nil
}