Skip to content
Open
7 changes: 0 additions & 7 deletions managed/models/agent_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,6 @@ type AgentFilters struct {
ServiceID string
// Return Agents with provided type.
AgentType *AgentType
// Return only Agents that provide insights for that AWSAccessKey.
AWSAccessKey string
// IgnoreNomad is used to ignore Nomad agents.
IgnoreNomad bool
// Disabled indicates whether to filter by disabled status.
Expand Down Expand Up @@ -267,11 +265,6 @@ func FindAgents(q *reform.Querier, filters AgentFilters) ([]*Agent, error) {
args = append(args, *filters.AgentType)
idx++
}
if filters.AWSAccessKey != "" {
conditions = append(conditions, fmt.Sprintf("(aws_options ? 'aws_access_key' AND aws_options->>'aws_access_key' = %s)", q.Placeholder(idx)))
args = append(args, filters.AWSAccessKey)
idx++
}
if filters.IgnoreNomad {
conditions = append(conditions, "agent_type != "+q.Placeholder(idx))
args = append(args, NomadAgentType)
Expand Down
9 changes: 7 additions & 2 deletions managed/services/agents/roster.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,19 @@ func (r *roster) get(groupID string) (string, []string, error) {
agentIDs = []string{PMMAgentID}
} else {
awsAccessKey := strings.TrimPrefix(parts[1], rdsPrefix)
filters := models.AgentFilters{PMMAgentID: PMMAgentID, AgentType: new(models.RDSExporterType), AWSAccessKey: awsAccessKey}
// aws_access_key is encrypted at rest, and FindAgents decrypts rows only
// after the WHERE clause, so a SQL filter on the access key never matches.
// Match it in Go on the decrypted value instead.
filters := models.AgentFilters{PMMAgentID: PMMAgentID, AgentType: new(models.RDSExporterType)}
agents, err := models.FindAgents(r.db.Querier, filters)
if err != nil {
return "", nil, err
}
agentIDs = make([]string, 0, len(agents))
for _, agent := range agents {
agentIDs = append(agentIDs, agent.AgentID)
if agent.AWSOptions.AWSAccessKey == awsAccessKey {
agentIDs = append(agentIDs, agent.AgentID)
}
}
}
}
Expand Down
36 changes: 36 additions & 0 deletions managed/services/agents/roster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,40 @@ func TestRoster(t *testing.T) {
assert.Equal(t, "pmm-server", PMMAgentID)
assert.Equal(t, []string{}, agentIDs)
})

// Regression test for the cold-cache DB fallback. aws_access_key is encrypted
// at rest, so resolving the group by an access key must work against the
// decrypted value. Seeding through the models API encrypts the key exactly as
// in production; get() runs on a cold roster (no prior add), exercising the
// fallback. This fails if get() filters the encrypted column in SQL and passes
// once the match is done in Go.
t.Run("GetFromDBEncryptedAccessKey", func(t *testing.T) {
r, teardown := setup(t)
defer teardown(t)

const awsAccessKey = "test-access-key"

node, err := models.CreateNode(r.db.Querier, models.RemoteRDSNodeType, &models.CreateNodeParams{
NodeName: "test-rds-roster-node",
Address: "rds-roster-test.xyzzy.us-east-1.rds.amazonaws.com",
Region: new("us-east-1"),
AZ: "us-east-1a",
InstanceID: "rds-roster-test",
})
require.NoError(t, err)

agent, err := models.CreateAgent(r.db.Querier, models.RDSExporterType, &models.CreateAgentParams{
PMMAgentID: models.PMMServerAgentID,
NodeID: node.NodeID,
AWSOptions: models.AWSOptions{AWSAccessKey: awsAccessKey},
})
require.NoError(t, err)

// Cold roster: no prior add(), so get() resolves members from the DB.
groupID := models.PMMServerAgentID + ":" + rdsPrefix + awsAccessKey
PMMAgentID, agentIDs, err := r.get(groupID)
require.NoError(t, err)
assert.Equal(t, models.PMMServerAgentID, PMMAgentID)
assert.Equal(t, []string{agent.AgentID}, agentIDs)
})
}