Skip to content

Commit 7103922

Browse files
authored
Auth policy: support for NotIpAddress condition operator (#9702)
1 parent 6818ac0 commit 7103922

File tree

3 files changed

+207
-104
lines changed

3 files changed

+207
-104
lines changed

docs/src/security/rbac.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ Conditions are added to policy statements using the optional `condition` field:
7777

7878
### Supported Condition Operators
7979

80-
#### IpAddress
80+
#### IpAddress / NotIpAddress
8181

82-
The `IpAddress` condition operator matches the client's source IP address against one or more IP addresses or CIDR blocks.
82+
The `IpAddress` condition operator matches the client's source IP address against one or more IP addresses or CIDR blocks. The `NotIpAddress` condition operator matches when the client's source IP address does NOT match any of the specified IP addresses or CIDR blocks (negation of `IpAddress`).
8383

8484
**Supported Fields:**
8585
- `SourceIp` - The IP address of the client making the request
@@ -127,6 +127,25 @@ The `IpAddress` condition operator matches the client's source IP address agains
127127
}
128128
```
129129

130+
**Example - Deny access from IPs NOT in allowed ranges:**
131+
132+
```json
133+
{
134+
"statement": [
135+
{
136+
"action": ["fs:*"],
137+
"effect": "deny",
138+
"resource": "*",
139+
"condition": {
140+
"NotIpAddress": {
141+
"SourceIp": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
142+
}
143+
}
144+
}
145+
]
146+
}
147+
```
148+
130149
**IP Address Extraction:**
131150

132151
lakeFS extracts the client IP address from the request using the following priority:

pkg/auth/condition.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import (
88
)
99

1010
const (
11-
OperatorNameIpAddress = "IpAddress"
11+
OperatorNameIpAddress = "IpAddress"
12+
OperatorNameNotIpAddress = "NotIpAddress"
1213
)
1314

1415
var (
@@ -36,7 +37,10 @@ type ConditionOperator interface {
3637

3738
// IpAddressOperator handles IP address matching with CIDR notation support
3839
// Dynamically checks all field names that contain IP addresses in the condition
39-
type IpAddressOperator struct{}
40+
type IpAddressOperator struct {
41+
// negate determines whether to negate the matching result
42+
negate bool
43+
}
4044

4145
// Validate implements ConditionOperator.
4246
func (op *IpAddressOperator) Validate(fields map[string][]string) error {
@@ -114,21 +118,24 @@ func (op *IpAddressOperator) Evaluate(fields map[string][]string, conditionCtx *
114118
return false, fmt.Errorf("%w in field %s: %s", ErrInvalidIPCIDRFormat, fieldName, value)
115119
}
116120

117-
// If this field didn't match any values, entire condition fails (AND logic between fields)
118-
if !fieldMatched {
121+
// For IpAddress: fail if field didn't match
122+
// For NotIpAddress: fail if field matched
123+
if fieldMatched == op.negate {
119124
return false, nil
120125
}
121126
}
122127

123-
// All fields matched
128+
// All fields processed successfully - condition passes
124129
return true, nil
125130
}
126131

127132
// OperatorFactory returns the appropriate operator for a given operator name
128133
func OperatorFactory(operatorName string) (ConditionOperator, error) {
129134
switch operatorName {
130135
case OperatorNameIpAddress:
131-
return &IpAddressOperator{}, nil
136+
return &IpAddressOperator{negate: false}, nil
137+
case OperatorNameNotIpAddress:
138+
return &IpAddressOperator{negate: true}, nil
132139
default:
133140
return nil, fmt.Errorf("%w: %s", ErrUnsupportedConditionOperator, operatorName)
134141
}

0 commit comments

Comments
 (0)