...

Source file src/github.com/Microsoft/hcsshim/internal/credentials/credentials.go

Documentation: github.com/Microsoft/hcsshim/internal/credentials

     1  //go:build windows
     2  // +build windows
     3  
     4  package credentials
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  
    12  	"github.com/Microsoft/hcsshim/internal/hcs"
    13  	hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
    14  	"github.com/Microsoft/hcsshim/internal/log"
    15  )
    16  
    17  // Container Credential Guard is in HCS's own words "The solution to
    18  // allowing windows containers to have access to domain credentials for the
    19  // applications running in their corresponding guest." It essentially acts as
    20  // a way to temporarily Active Directory join a given container with a Group
    21  // Managed Service Account (GMSA for short) credential specification.
    22  // CCG will launch a process in the host that will act as a middleman for the
    23  // credential passthrough logic. The guest is then configured through registry
    24  // keys to have access to the process in the host.
    25  // A CCG instance needs to be created through various HCS calls and then added to
    26  // the V2 schema container document before being sent to HCS. For V1 HCS schema containers
    27  // setting up instances manually is not needed, the GMSA credential specification
    28  // simply needs to be present in the V1 container document.
    29  
    30  // CCGResource stores the id used when creating a ccg instance. Used when
    31  // closing a container to be able to release the instance.
    32  type CCGResource struct {
    33  	// ID of container that instance belongs to.
    34  	id string
    35  }
    36  
    37  // Release calls into hcs to remove the ccg instance for the container matching CCGResource.id.
    38  // These do not get cleaned up automatically they MUST be explicitly removed with a call to
    39  // ModifyServiceSettings. The instances will persist unless vmcompute.exe exits or they are removed
    40  // manually as done here.
    41  func (ccgResource *CCGResource) Release(ctx context.Context) error {
    42  	if err := removeCredentialGuard(ctx, ccgResource.id); err != nil {
    43  		return fmt.Errorf("failed to remove container credential guard instance: %s", err)
    44  	}
    45  	return nil
    46  }
    47  
    48  // CreateCredentialGuard creates a container credential guard instance and
    49  // returns the state object to be placed in a v2 container doc.
    50  func CreateCredentialGuard(ctx context.Context, id, credSpec string, hypervisorIsolated bool) (*hcsschema.ContainerCredentialGuardInstance, *CCGResource, error) {
    51  	log.G(ctx).WithField("containerID", id).Debug("creating container credential guard instance")
    52  	// V2 schema ccg setup a little different as its expected to be passed
    53  	// through all the way to the gcs. Can no longer be enabled just through
    54  	// a single property. The flow is as follows
    55  	// ------------------------------------------------------------------------
    56  	// 1. Call HcsModifyServiceSettings with a ModificationRequest set with a
    57  	// ContainerCredentialGuardAddInstanceRequest. This is where the cred spec
    58  	// gets passed in. Transport either "LRPC" (Argon) or "HvSocket" (Xenon).
    59  	//
    60  	// 2. Query the instance with a call to HcsGetServiceProperties with the
    61  	// PropertyType "ContainerCredentialGuard". This will return all instances
    62  	//
    63  	// 3. Parse for the id of our container to find which one correlates to the
    64  	// container we're building the doc for, then add to the V2 doc.
    65  	//
    66  	// 4. If xenon container the CCG instance with the Hvsocket service table
    67  	// information is expected to be in the Utility VMs doc before being sent
    68  	// to HCS for creation. For pod scenarios currently we don't have the OCI
    69  	// spec of a container at UVM creation time, therefore the service table entry
    70  	// for the CCG instance will have to be hot added.
    71  	transport := "LRPC"
    72  	if hypervisorIsolated {
    73  		transport = "HvSocket"
    74  	}
    75  	req := hcsschema.ModificationRequest{
    76  		PropertyType: hcsschema.PTContainerCredentialGuard,
    77  		Settings: &hcsschema.ContainerCredentialGuardOperationRequest{
    78  			Operation: hcsschema.AddInstance,
    79  			OperationDetails: &hcsschema.ContainerCredentialGuardAddInstanceRequest{
    80  				Id:             id,
    81  				CredentialSpec: credSpec,
    82  				Transport:      transport,
    83  			},
    84  		},
    85  	}
    86  	if err := hcs.ModifyServiceSettings(ctx, req); err != nil {
    87  		return nil, nil, fmt.Errorf("failed to generate container credential guard instance: %s", err)
    88  	}
    89  
    90  	q := hcsschema.PropertyQuery{
    91  		PropertyTypes: []hcsschema.PropertyType{hcsschema.PTContainerCredentialGuard},
    92  	}
    93  	serviceProps, err := hcs.GetServiceProperties(ctx, q)
    94  	if err != nil {
    95  		return nil, nil, fmt.Errorf("failed to retrieve container credential guard instances: %s", err)
    96  	}
    97  	if len(serviceProps.Properties) != 1 {
    98  		return nil, nil, errors.New("wrong number of service properties present")
    99  	}
   100  
   101  	ccgSysInfo := &hcsschema.ContainerCredentialGuardSystemInfo{}
   102  	if err := json.Unmarshal(serviceProps.Properties[0], ccgSysInfo); err != nil {
   103  		return nil, nil, fmt.Errorf("failed to unmarshal container credential guard instances: %s", err)
   104  	}
   105  	for _, ccgInstance := range ccgSysInfo.Instances {
   106  		if ccgInstance.Id == id {
   107  			ccgResource := &CCGResource{
   108  				id,
   109  			}
   110  			return &ccgInstance, ccgResource, nil
   111  		}
   112  	}
   113  	return nil, nil, fmt.Errorf("failed to find credential guard instance with container ID %s", id)
   114  }
   115  
   116  // Removes a ContainerCredentialGuard instance by container ID.
   117  func removeCredentialGuard(ctx context.Context, id string) error {
   118  	log.G(ctx).WithField("containerID", id).Debug("removing container credential guard")
   119  
   120  	req := hcsschema.ModificationRequest{
   121  		PropertyType: hcsschema.PTContainerCredentialGuard,
   122  		Settings: &hcsschema.ContainerCredentialGuardOperationRequest{
   123  			Operation: hcsschema.RemoveInstance,
   124  			OperationDetails: &hcsschema.ContainerCredentialGuardRemoveInstanceRequest{
   125  				Id: id,
   126  			},
   127  		},
   128  	}
   129  	return hcs.ModifyServiceSettings(ctx, req)
   130  }
   131  

View as plain text