@@ -634,6 +634,66 @@ func WithUsername(username string) SpecOpts {
634634 }
635635}
636636
637+ // WithAdditionalGIDs sets the OCI spec's additionalGids array to any additional groups listed
638+ // for a particular user in the /etc/groups file of the image's root filesystem
639+ func WithAdditionalGIDs (username string ) SpecOpts {
640+ return func (ctx context.Context , client Client , c * containers.Container , s * Spec ) (err error ) {
641+ setProcess (s )
642+ if c .Snapshotter == "" && c .SnapshotKey == "" {
643+ if ! isRootfsAbs (s .Root .Path ) {
644+ return errors .Errorf ("rootfs absolute path is required" )
645+ }
646+ gids , err := getSupplementalGroupsFromPath (s .Root .Path , func (g user.Group ) bool {
647+ // we only want supplemental groups
648+ if g .Name == username {
649+ return false
650+ }
651+ for _ , entry := range g .List {
652+ if entry == username {
653+ return true
654+ }
655+ }
656+ return false
657+ })
658+ if err != nil {
659+ return err
660+ }
661+ s .Process .User .AdditionalGids = gids
662+ return nil
663+ }
664+ if c .Snapshotter == "" {
665+ return errors .Errorf ("no snapshotter set for container" )
666+ }
667+ if c .SnapshotKey == "" {
668+ return errors .Errorf ("rootfs snapshot not created for container" )
669+ }
670+ snapshotter := client .SnapshotService (c .Snapshotter )
671+ mounts , err := snapshotter .Mounts (ctx , c .SnapshotKey )
672+ if err != nil {
673+ return err
674+ }
675+ return mount .WithTempMount (ctx , mounts , func (root string ) error {
676+ gids , err := getSupplementalGroupsFromPath (root , func (g user.Group ) bool {
677+ // we only want supplemental groups
678+ if g .Name == username {
679+ return false
680+ }
681+ for _ , entry := range g .List {
682+ if entry == username {
683+ return true
684+ }
685+ }
686+ return false
687+ })
688+ if err != nil {
689+ return err
690+ }
691+ s .Process .User .AdditionalGids = gids
692+ return nil
693+ })
694+ }
695+ }
696+
637697// WithCapabilities sets Linux capabilities on the process
638698func WithCapabilities (caps []string ) SpecOpts {
639699 return func (_ context.Context , _ Client , _ * containers.Container , s * Spec ) error {
@@ -715,6 +775,26 @@ func getGIDFromPath(root string, filter func(user.Group) bool) (gid uint32, err
715775 return uint32 (g .Gid ), nil
716776}
717777
778+ func getSupplementalGroupsFromPath (root string , filter func (user.Group ) bool ) ([]uint32 , error ) {
779+ gpath , err := fs .RootPath (root , "/etc/group" )
780+ if err != nil {
781+ return []uint32 {}, err
782+ }
783+ groups , err := user .ParseGroupFileFilter (gpath , filter )
784+ if err != nil {
785+ return []uint32 {}, err
786+ }
787+ if len (groups ) == 0 {
788+ // if there are no additional groups; just return an empty set
789+ return []uint32 {}, nil
790+ }
791+ addlGids := []uint32 {}
792+ for _ , grp := range groups {
793+ addlGids = append (addlGids , uint32 (grp .Gid ))
794+ }
795+ return addlGids , nil
796+ }
797+
718798func isRootfsAbs (root string ) bool {
719799 return filepath .IsAbs (root )
720800}
0 commit comments