Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ and the existing exceptions enforced on host and platform vulnerabilities will b
Instead, only the associated role names will be there. Enabling this will lower the verbosity of the audit log messages,
but investigating associated permissions for a requester might be harder (i.e. the associated role would have be known at the time of the request).
Thus, it is generally not recommended to set this to `true`.
- ROX-18978: The default policy "Iptables Executed in Privileged Container" has been renamed to "Iptables or nftables Executed in Privileged Container" and now also detects the `nft` process which is used by `nftables`.

## [4.2.0]

Expand Down
4 changes: 2 additions & 2 deletions migrator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ To freeze a schema, you can use the following tool to generate a frozen schema,
to generate current schema which can be find in each Postgres store.

```shell
pg-schema-migration-helper --type=<prototype> --search-category ...
./tools/generate-helpers/pg-schema-migration-helper --type=<prototype> --search-category ...
```

This tool also generates conversion tools for schema, you may remove them.
Expand Down Expand Up @@ -289,7 +289,7 @@ The following shows an example of the conversion functions.
The tool is `pg-schema-migration-helper`, it can be used as follows.

```shell
pg-schema-migration-helper --type=storage.VulnerabilityRequest --search-category VULN_REQUEST
./tools/generate-helpers/pg-schema-migration-helper --type=storage.VulnerabilityRequest --search-category VULN_REQUEST
```

`pg-schema-migration-helper` uses the same elements as `pg-table-bindings-wrapper` (the code generator for the postgres
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package m193tom194

import (
"context"
"embed"

"github.com/pkg/errors"
"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/migrator/migrations"
"github.com/stackrox/rox/migrator/migrations/m_193_to_m_194_policy_updates_for_4_3/schema"
"github.com/stackrox/rox/migrator/migrations/policymigrationhelper"
"github.com/stackrox/rox/migrator/types"
"gorm.io/gorm"
)

var (
migration = types.Migration{
StartingSeqNum: 193,
VersionAfter: &storage.Version{SeqNum: 194},
Run: func(databases *types.Databases) error {
err := updatePolicies(databases.GormDB)
if err != nil {
return errors.Wrap(err, "updating policies")
}
return nil
},
}

//go:embed policies_before_and_after
policyDiffFS embed.FS

// Update only if the existing name, description and policy sections haven't changed.
fieldsToCompare = []policymigrationhelper.FieldComparator{
policymigrationhelper.NameComparator,
policymigrationhelper.DescriptionComparator,
policymigrationhelper.PolicySectionComparator,
}

// Update the nftables policy only if the existing name, description, rationale, remediation and policy sections haven't changed.
nftablesFieldsToCompare = []policymigrationhelper.FieldComparator{
policymigrationhelper.NameComparator,
policymigrationhelper.DescriptionComparator,
policymigrationhelper.RationaleComparator,
policymigrationhelper.RemediationComparator,
policymigrationhelper.PolicySectionComparator,
}

policyDiffs = []policymigrationhelper.PolicyDiff{
{
FieldsToCompare: nftablesFieldsToCompare,
PolicyFileName: "exec-iptables-root.json",
},
{
FieldsToCompare: fieldsToCompare,
PolicyFileName: "process_uid_zero.json",
},
}
)

func updatePolicies(db *gorm.DB) error {

return policymigrationhelper.MigratePoliciesWithDiffsAndStoreV2(
policyDiffFS,
policyDiffs,
// Get policy with specified id
func(ctx context.Context, id string) (*storage.Policy, bool, error) {
var foundPolicy schema.Policies
result := db.WithContext(ctx).Table(schema.PoliciesTableName).Where(&schema.Policies{ID: id}).First(&foundPolicy)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, result.Error
}
storagePolicy, err := schema.ConvertPolicyToProto(&foundPolicy)
if err != nil {
return nil, false, err
}
return storagePolicy, true, nil
},
// Upsert policy. Technically it should be just an update and not create because in theory policy has been verified to exist
func(ctx context.Context, policy *storage.Policy) error {
dbPolicy, err := schema.ConvertPolicyFromProto(policy)
if err != nil {
return err
}
result := db.WithContext(ctx).Table(schema.PoliciesTableName).Save(dbPolicy)
if result.RowsAffected != 1 {
return errors.Errorf("failed to save policy with id %s", policy.GetId())
}
return result.Error
},
)
}

func init() {
migrations.MustRegisterMigration(migration)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//go:build sql_integration

package m193tom194

import (
"context"
"fmt"
"path/filepath"
"testing"

"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/migrator/migrations/m_193_to_m_194_policy_updates_for_4_3/schema"
"github.com/stackrox/rox/migrator/migrations/policymigrationhelper"
pghelper "github.com/stackrox/rox/migrator/migrations/postgreshelper"
"github.com/stackrox/rox/migrator/types"
"github.com/stackrox/rox/pkg/postgres/pgutils"
"github.com/stackrox/rox/pkg/sac"
"github.com/stretchr/testify/suite"
"gorm.io/gorm"
)

type policyMigrationTestSuite struct {
suite.Suite

db *pghelper.TestPostgres
gormDB *gorm.DB

ctx context.Context
}

func TestMigration(t *testing.T) {
suite.Run(t, new(policyMigrationTestSuite))
}

func simplePolicy(policyID string) *storage.Policy {
return &storage.Policy{
Id: policyID,
Name: fmt.Sprintf("Policy with id %s", policyID),
}
}

func (s *policyMigrationTestSuite) SetupTest() {
s.ctx = sac.WithAllAccess(context.Background())

s.db = pghelper.ForT(s.T(), false)
s.gormDB = s.db.GetGormDB().WithContext(s.ctx)
pgutils.CreateTableFromModel(s.ctx, s.db.GetGormDB(), schema.CreateTablePoliciesStmt)

// insert other un policies that won't be migrated in the db for migration to run successfully
policies := []*storage.Policy{
simplePolicy("47cb9e0a-879a-417b-9a8f-de644d7c8a77"),
simplePolicy("6226d4ad-7619-4a0b-a160-46373cfcee66"),
simplePolicy("436811e7-892f-4da6-a0f5-8cc459f1b954"),
simplePolicy("742e0361-bddd-4a2d-8758-f2af6197f61d"),
simplePolicy("16c95922-08c4-41b6-a721-dc4b2a806632"),
simplePolicy("a9b9ecf7-9707-4e32-8b62-d03018ed454f"),
simplePolicy("32d770b9-c6ba-4398-b48a-0c3e807644ed"),
}

for _, p := range policies {
s.addPolicyToDB(p)
}
}

func (s *policyMigrationTestSuite) TearDownTest() {
s.db.Teardown(s.T())
}

func (s *policyMigrationTestSuite) TestMigration() {

// Insert the policies to be migrated
for _, diff := range policyDiffs {
beforePolicy, err := policymigrationhelper.ReadPolicyFromFile(policyDiffFS, filepath.Join("policies_before_and_after/before", diff.PolicyFileName))
s.Require().NoError(err)
s.addPolicyToDB(beforePolicy)
}

// Run the migration
s.Require().NoError(migration.Run(&types.Databases{
PostgresDB: s.db.DB,
GormDB: s.gormDB,
}))

// Verify for each
for _, diff := range policyDiffs {
s.Run(fmt.Sprintf("Testing policy %s", diff.PolicyFileName), func() {

afterPolicy, _ := policymigrationhelper.ReadPolicyFromFile(policyDiffFS, filepath.Join("policies_before_and_after/after", diff.PolicyFileName))
var foundPolicies []schema.Policies
result := s.gormDB.Limit(1).Where(&schema.Policies{ID: afterPolicy.GetId()}).Find(&foundPolicies)
s.Require().NoError(result.Error)
migratedPolicy, err := schema.ConvertPolicyToProto(&foundPolicies[0])
s.Require().NoError(err)
s.Equal(afterPolicy, migratedPolicy)
})
}
}

func (s *policyMigrationTestSuite) addPolicyToDB(policy *storage.Policy) {
p, err := schema.ConvertPolicyFromProto(policy)
s.Require().NoError(err)
s.Require().NoError(s.gormDB.Create(p).Error)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{
"id": "ed8c7957-14de-40bc-aeab-d27ceeecfa7b",
"name": "Iptables or nftables Executed in Privileged Container",
"description": "Alert on privileged pods that execute iptables or nftables",
"rationale": "Processes that are running with UID 0 run as the root user. iptables and nftables can be used in privileged containers to modify the node's network routing.",
"remediation": "Specify the USER instruction in the Docker image or the runAsUser field within the Pod Security Context",
"categories": [
"Network Tools",
"Security Best Practices"
],
"lifecycleStages": [
"RUNTIME"
],
"eventSource": "DEPLOYMENT_EVENT",
"exclusions": [
{
"name": "Don't alert on haproxy-* deployment in openshift-vsphere-infra namespace",
"deployment": {
"name": "haproxy-.*",
"scope": {
"namespace": "openshift-vsphere-infra"
}
}
},
{
"name": "Don't alert on keepalived-* deployment in openshift-vsphere-infra namespace",
"deployment": {
"name": "keepalived-.*",
"scope": {
"namespace": "openshift-vsphere-infra"
}
}
},
{
"name": "Don't alert on coredns-* deployment in openshift-vsphere-infra namespace",
"deployment": {
"name": "coredns-.*",
"scope": {
"namespace": "openshift-vsphere-infra"
}
}
},
{
"name": "Don't alert on ovnkube-node deployment in openshift-ovn-kubernetes Namespace",
"deployment": {
"name": "ovnkube-node",
"scope": {
"namespace": "openshift-ovn-kubernetes"
}
}
},
{
"name": "Don't alert on Kube System Namespace",
"deployment": {
"scope": {
"namespace": "kube-system"
}
}
},
{
"name": "Don't alert on istio-system namespace",
"deployment": {
"scope": {
"namespace": "istio-system"
}
}
},
{
"name": "Don't alert on openshift-sdn namespace",
"deployment": {
"scope": {
"namespace": "openshift-sdn"
}
}
}
],
"severity": "CRITICAL_SEVERITY",
"policyVersion": "1.1",
"policySections": [
{
"policyGroups": [
{
"fieldName": "Privileged Container",
"values": [
{
"value": "true"
}
]
},
{
"fieldName": "Process Name",
"values": [
{
"value": "iptables"
},
{
"value": "nft"
}
]
},
{
"fieldName": "Process UID",
"values": [
{
"value": "0"
}
]
}
]
}
],
"mitreAttackVectors": [
{
"tactic": "TA0004",
"techniques": [
"T1611"
]
},
{
"tactic": "TA0005",
"techniques": [
"T1562.004"
]
}
],
"criteriaLocked": true,
"mitreVectorsLocked": true,
"isDefault": true
}
Loading