Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat support security fsgroup #1613

Merged
merged 4 commits into from
Apr 5, 2023
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
15 changes: 15 additions & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ The currently supported options are:
| kompose.service.healthcheck.liveness.http_get_port | kubernetes liveness httpGet port |
| kompose.service.healthcheck.liveness.tcp_port | kubernetes liveness tcpSocket port |
| kompose.service.external-traffic-policy | 'cluster', 'local', '' | |
| kompose.security-context.fsgroup | kubernetes pod security group fsgroup | |

**Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail.

Expand Down Expand Up @@ -431,6 +432,20 @@ services:
kompose.service.external-traffic-policy: local
kompose.service.type: loadbalancer
```

- `kompose.security-context.fsgroup` defines Kubernetes Pod [security context FsGroup.](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).

For example:

```yaml
version: '3.8'

services:
pgadmin:
image: nginx
labels:
kompose.security-context.fsgroup: 1001
```
## Restart

If you want to create normal pods without controller you can use `restart` construct of docker-compose to define that. Follow table below to see what happens on the `restart` value.
Expand Down
1 change: 1 addition & 0 deletions pkg/kobject/kobject.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ type ServiceConfig struct {
Dockerfile string `compose:"dockerfile"`
Replicas int `compose:"replicas"`
GroupAdd []int64 `compose:"group_add"`
FsGroup int64 `compose:"kompose.security-context.fsgroup"`
Volumes []Volumes `compose:""`
Secrets []types.ServiceSecretConfig
HealthChecks HealthChecks `compose:""`
Expand Down
2 changes: 2 additions & 0 deletions pkg/loader/compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,8 @@ func parseKomposeLabels(labels map[string]string, serviceConfig *kobject.Service
}

serviceConfig.ServiceExternalTrafficPolicy = serviceExternalTypeTrafficPolicy
case LabelSecurityContextFsGroup:
serviceConfig.FsGroup = cast.ToInt64(value)
case LabelServiceExpose:
serviceConfig.ExposeService = strings.Trim(strings.ToLower(value), " ,")
case LabelNodePortPort:
Expand Down
2 changes: 2 additions & 0 deletions pkg/loader/compose/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ const (

// ServiceTypeHeadless ...
ServiceTypeHeadless = "Headless"
// LabelSecurityContextFsGroup defines the pod FsGroup
LabelSecurityContextFsGroup = "kompose.security-context.fsgroup"
)

// load environment variables from compose file
Expand Down
5 changes: 5 additions & 0 deletions pkg/transformer/kubernetes/k8sutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,11 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
podSecurityContext.SupplementalGroups = service.GroupAdd
}

//set Security Context FsGroup
if service.FsGroup != 0 {
podSecurityContext.FSGroup = &service.FsGroup
}

// Setup security context
securityContext := &api.SecurityContext{}
if service.Privileged {
Expand Down
4 changes: 4 additions & 0 deletions pkg/transformer/kubernetes/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func newServiceConfig() kobject.ServiceConfig {
VolList: []string{"/tmp/volume"},
Network: []string{"network1", "network2"}, // supported
Labels: nil,
FsGroup: 1001,
Annotations: map[string]string{"abc": "def"},
CPUQuota: 1, // not supported
CapAdd: []string{"cap_add"},
Expand Down Expand Up @@ -209,6 +210,9 @@ func checkPodTemplate(config kobject.ServiceConfig, template api.PodTemplateSpec
if config.Privileged == privilegedNilOrFalse(template) {
return fmt.Errorf("Found different template privileged: %#v vs. %#v", config.Privileged, template.Spec.Containers[0].SecurityContext)
}
if config.FsGroup != *template.Spec.SecurityContext.FSGroup {
return fmt.Errorf("Found different pod security context fs group values: %#v vs. %#v", config.FsGroup, *template.Spec.SecurityContext.FSGroup)
}
if config.Stdin != template.Spec.Containers[0].Stdin {
return fmt.Errorf("Found different values for stdin: %#v vs. %#v", config.Stdin, template.Spec.Containers[0].Stdin)
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/transformer/kubernetes/podspec.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ func SecurityContext(name string, service kobject.ServiceConfig) PodSpecOption {
podSecurityContext.SupplementalGroups = service.GroupAdd
}

//set Pod FsGroup
if service.FsGroup != 0 {
podSecurityContext.FSGroup = &service.FsGroup
}

// Setup security context
securityContext := &api.SecurityContext{}
if service.Privileged {
Expand Down
8 changes: 8 additions & 0 deletions script/test/cmd/tests_new.sh
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,11 @@ os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/exter
os_output="$KOMPOSE_ROOT/script/test/fixtures/external-traffic-policy/output-os-v2.yaml"
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output"
convert::expect_success_and_warning "$os_cmd" "$os_output"

# Test Pod security context fs group
k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/fsgroup/docker-compose.yaml convert --stdout --with-kompose-annotation=false"
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/fsgroup/output-k8s.yaml"
os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/fsgroup/docker-compose.yaml convert --stdout --with-kompose-annotation=false"
os_output="$KOMPOSE_ROOT/script/test/fixtures/fsgroup/output-os.yaml"
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output"
convert::expect_success "$os_cmd" "$os_output"
14 changes: 14 additions & 0 deletions script/test/fixtures/fsgroup/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: '3.8'
volumes:
pgadmin-data:

services:
pgadmin:
labels:
kompose.security-context.fsgroup: 1001
image: dpage/pgadmin4
environment:
PGADMIN_DEFAULT_EMAIL: dumb_pgadmin_user@email.com
PGADMIN_DEFAULT_PASSWORD: pgadmin_password
volumes:
- pgadmin-data:/var/lib/pgadmin
79 changes: 79 additions & 0 deletions script/test/fixtures/fsgroup/output-k8s.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kompose.security-context.fsgroup: "1001"
creationTimestamp: null
labels:
io.kompose.service: pgadmin
name: pgadmin
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: pgadmin
strategy:
type: Recreate
template:
metadata:
annotations:
kompose.security-context.fsgroup: "1001"
creationTimestamp: null
labels:
io.kompose.network/fsgroup-default: "true"
io.kompose.service: pgadmin
spec:
containers:
- env:
- name: PGADMIN_DEFAULT_EMAIL
value: dumb_pgadmin_user@email.com
- name: PGADMIN_DEFAULT_PASSWORD
value: pgadmin_password
image: dpage/pgadmin4
name: pgadmin
resources: {}
volumeMounts:
- mountPath: /var/lib/pgadmin
name: pgadmin-data
restartPolicy: Always
securityContext:
fsGroup: 1001
volumes:
- name: pgadmin-data
persistentVolumeClaim:
claimName: pgadmin-data
status: {}

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
creationTimestamp: null
labels:
io.kompose.service: pgadmin-data
name: pgadmin-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
status: {}

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
creationTimestamp: null
name: fsgroup-default
spec:
ingress:
- from:
- podSelector:
matchLabels:
io.kompose.network/fsgroup-default: "true"
podSelector:
matchLabels:
io.kompose.network/fsgroup-default: "true"

102 changes: 102 additions & 0 deletions script/test/fixtures/fsgroup/output-os.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
apiVersion: v1
kind: DeploymentConfig
metadata:
annotations:
kompose.security-context.fsgroup: "1001"
creationTimestamp: null
labels:
io.kompose.service: pgadmin
name: pgadmin
spec:
replicas: 1
selector:
io.kompose.service: pgadmin
strategy:
resources: {}
type: Recreate
template:
metadata:
creationTimestamp: null
labels:
io.kompose.network/fsgroup-default: "true"
io.kompose.service: pgadmin
spec:
containers:
- env:
- name: PGADMIN_DEFAULT_EMAIL
value: dumb_pgadmin_user@email.com
- name: PGADMIN_DEFAULT_PASSWORD
value: pgadmin_password
image: ' '
name: pgadmin
resources: {}
volumeMounts:
- mountPath: /var/lib/pgadmin
name: pgadmin-data
restartPolicy: Always
securityContext:
fsGroup: 1001
volumes:
- name: pgadmin-data
persistentVolumeClaim:
claimName: pgadmin-data
test: false
triggers:
- type: ConfigChange
- imageChangeParams:
automatic: true
containerNames:
- pgadmin
from:
kind: ImageStreamTag
name: pgadmin:latest
type: ImageChange
status:
availableReplicas: 0
latestVersion: 0
observedGeneration: 0
replicas: 0
unavailableReplicas: 0
updatedReplicas: 0

---
apiVersion: v1
kind: ImageStream
metadata:
creationTimestamp: null
labels:
io.kompose.service: pgadmin
name: pgadmin
spec:
lookupPolicy:
local: false
tags:
- annotations: null
from:
kind: DockerImage
name: dpage/pgadmin4
generation: null
importPolicy: {}
name: latest
referencePolicy:
type: ""
status:
dockerImageRepository: ""

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
creationTimestamp: null
labels:
io.kompose.service: pgadmin-data
name: pgadmin-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
status: {}