GithubHelp home page GithubHelp logo

aws / credentials-fetcher Goto Github PK

View Code? Open in Web Editor NEW
89.0 20.0 22.0 7.1 MB

Credentials-fetcher is a Linux daemon that retrieves gMSA credentials from Active Directory over LDAP. It creates and refreshes kerberos tickets from gMSA credentials. Kerberos tickets can be used by containers to run apps/services that authenticate using Active Directory.

License: Apache License 2.0

CMake 3.24% C++ 45.33% Shell 0.60% PowerShell 0.57% C# 0.16% C 50.11%

credentials-fetcher's Introduction

Credentials Fetcher

credentials-fetcher is a Linux daemon that retrieves gMSA credentials from Active Directory over LDAP. It creates and refreshes kerberos tickets from gMSA credentials. Kerberos tickets can be used by containers to run apps/services that authenticate using Active Directory.

This daemon works in a similar way as ccg.exe and the gMSA plugin in Windows as described in - https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts#gmsa-architecture-and-improvements

How to install and run

On Fedora 36 and similar distributions, the binary RPM can be installed as sudo dnf install credentials-fetcher. You can also use yum if dnf is not present. The daemon can be started using sudo systemctl start credentials-fetcher.

On Enterprise Linux 9 ( RHEL | CentOS | AlmaLinux ), the binary can be installed from EPEL. To add EPEL, see the EPEL Quickstart. Once EPEL is enabled, install credentials-fetcher with sudo dnf install credentials-fetcher.

For other linux distributions, the daemon binary needs to be built from source code.

Development

Prerequisites

Create credentialspec associated with gMSA account:

  • Create a domain joined windows instance
  • Install powershell module - "Install-Module CredentialSpec"
  • New-CredentialSpec -AccountName WebApp01 // Replace 'WebApp01' with your own gMSA
  • You will find the credentialspec in the directory 'C:\Program Data\Docker\Credentialspecs\WebApp01_CredSpec.json'

Standalone mode

To start a local dev environment from scratch:

* Clone the Git repository.
* cd credentials-fetcher && mkdir build
* cd build && cmake ../ && make -j
* ./credentials-fetcher to start the program in non-daemon mode.

Testing

To communicate with the daemon over gRPC, install grpc-cli. For example sudo yum install grpc-cli

AddKerberosLease API:

Note: APIs use unix domain socket

Invoke the AddkerberosLease API with the credentialsspec input as shown:
grpc_cli call {unix_domain_socket} AddKerberosLease "credspec_contents: '{credentialspec}'"

Sample:
grpc_cli call unix:/var/credentials-fetcher/socket/credentials_fetcher.sock
AddKerberosLease "credspec_contents: '{\"CmsPlugins\":[\"ActiveDirectory\"],\"DomainJoinConfig\":{\"Sid\":\"S-1-5-21-4217655605-3681839426-3493040985\",
\"MachineAccountName\":\"WebApp01\",\"Guid\":\"af602f85-d754-4eea-9fa8-fd76810485f1\",\"DnsTreeName\":\"contoso.com\",
\"DnsName\":\"contoso.com\",\"NetBiosName\":\"contoso\"},\"ActiveDirectoryConfig\":{\"GroupManagedServiceAccounts\":[{\"Name\":\"WebApp01\",\"Scope\":\"contoso.com\"}
,{\"Name\":\"WebApp01\",\"Scope\":\"contoso\"}]}}'"

* Response:
  lease_id - unique identifier associated to the request
  created_kerberos_file_paths - Paths associated to the Kerberos tickets created corresponding to the gMSA accounts
DeleteKerberosLease API:
Invoke the Delete kerberosLease API with lease id input as shown:
grpc_cli call {unix_domain_socket} DeleteKerberosLease "lease_id: '{lease_id}'"

Sample:
grpc_cli call unix:/var/credentials-fetcher/socket/credentials_fetcher.sock DeleteKerberosLease "lease_id: '${response_lease_id_from_add_kerberos_lease}'"

* Response:
    lease_id - unique identifier associated to the request
    deleted_kerberos_file_paths - Paths associated to the Kerberos tickets deleted corresponding to the gMSA accounts

Logging

Logs about request/response to the daemon and any failures.

journalctl -u credentials-fetcher

Default environment variables

Environment Key Examples values Description
CF_KRB_DIR '/var/credentials-fetcher/krbdir' (Default) Dir path for storing the kerberos tickets
CF_UNIX_DOMAIN_SOCKET_DIR '/var/credentials-fetcher/socket' (Default) Dir path for the domain socker for gRPC communication 'credentials_fetcher.sock'
CF_LOGGING_DIR '/var/credentials-fetcher/logging' (Default) Dir Path for log
CF_TEST_DOMAIN_NAME 'contoso.com' Test domain name
CF_TEST_GMSA_ACCOUNT 'webapp01' Test gMSA account name

Runtime environment variables

Environment Variable Examples values Description
CF_CRED_SPEC_FILE '/var/credentials-fetcher/my-credspec.json' Path to a credential spec file used as input. (Lease id default: credspec)
'/var/credentials-fetcher/my-credspec.json:myLeaseId' An optional lease id specified after a colon
CF_GMSA_OU 'CN=Managed Service Accounts' Component of GMSA distinguished name (see docs/cf_gmsa_ou.md)

Compatibility

Running the Credentials-fetcher outside of Linux distributions is not supported.

Contributing

Contributions and feedback are welcome! Proposals and pull requests will be considered and responded to. For more information, see the CONTRIBUTING.md file. If you have a bug/and issue around the behavior of the credentials-fetcher, please open it here.

Amazon Web Services does not currently provide support for modified copies of this software.

Security disclosures

If you think you’ve found a potential security issue, please do not post it in the Issues. Instead, please follow the instructions here or email AWS security directly.

License

The Credentials Fetcher is licensed under the Apache 2.0 License. See LICENSE and NOTICE for more information.

credentials-fetcher's People

Contributors

as14692 avatar beau-gosse-dev avatar bhallasaksham avatar cskumar6381 avatar ford-th avatar fordth avatar gustavo-armenta avatar heathhey avatar jamolina avatar justas05 avatar saikiranakula-amzn avatar sb-ruisms avatar smhmhmd avatar spotaws avatar spotrh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

credentials-fetcher's Issues

Build error in Docker ubuntu-22.04

/root/credentials-fetcher/api/src/gmsa_service.cpp:4:10: fatal error: 'credentialsfetcher.grpc.pb.h' file not found
#include <credentialsfetcher.grpc.pb.h>
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
make[2]: *** [api/CMakeFiles/cf_gmsa_service_private.dir/build.make:79: api/CMakeFiles/cf_gmsa_service_private.dir/src/gmsa_service.cpp.o] Error 1
make[2]: Leaving directory '/root/credentials-fetcher/build'
make[1]: *** [CMakeFiles/Makefile2:247: api/CMakeFiles/cf_gmsa_service_private.dir/all] Error 2
make[1]: Leaving directory '/root/credentials-fetcher/build'
make: *** [Makefile:139: all] Error 2

Support Alpine Linux

Support for Alpine Linux would be very beneficial.

Excited about this project launch, it will solve a big problem for us. Thanks!

Add keytab support for SPNEGO apps

As per this discussion, add keytab support.

It looks possible to extend credentials-fetcher to manipulate keytab files.
Keytab files can be shared with containers just like Kerberos tickets are being shared as of now.
This can be done with non-gMSA accounts as well, as long as password expiry interval is known.
If the password expiry interval is longer than keytab file refresh, this would work fine.

Containers not running as root (Informational)

Dockerfile images that contain something of the following so within the container is run as non root user:
RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app

This will cause the kerberos client inside the container to not have access to the TGT created on the host by credentials-fetcher.

parse_options() in config.cpp ignores aws_sm_secret_name parameter passed via command line

The logic sets the variable then overrides it later with ECS config:

//snippet where value is retrieved from command line parameters

        case 's':
            cf_daemon.aws_sm_secret_name = optarg;
            std::cout << "Option selected for domainless operation, AWS secrets manager "
                         "secret-name = " << optarg << std::endl;
            break;

//snippet later in function overrides

std::string aws_sm_secret_name = retrieve_secret_from_ecs_config(domainless_gmsa_field);
cf_daemon.aws_sm_secret_name = aws_sm_secret_name;

Replace mono with dotnet

Mono is currently used to compile the C# code for UTF-16, the task is to use dotnet if it available instead of mono in Linux.

ProcessCredSpecFile() makes call to get_machine_krb_ticket() when running in Domainless mode

ProcessCredSpecFile() should have logic like this:

    if ( aws_sm_secret_name.length() != 0 )
    {
        status = get_user_krb_ticket( krb_ticket_info->domain_name,
                                      aws_sm_secret_name, cf_logger );
        krb_ticket_info->domainless_user =
            "awsdomainlessusersecret:"+aws_sm_secret_name;

        if ( status < 0 )
        {
            cf_logger.logger( LOG_ERR, "Error %d: Cannot get usr krb ticket",
                                status );
            delete krb_ticket_info;
           return EXIT_FAILURE;
        }
}
    else
    {
        // invoke to get machine ticket
        status = get_machine_krb_ticket( krb_ticket_info->domain_name, cf_logger );
        if ( status < 0 )
    {
        cf_logger.logger( LOG_ERR, "Error %d: Cannot get machine krb ticket",
                            status );
        delete krb_ticket_info;
           return EXIT_FAILURE;
        }
    }

Ticket Expiration vs Renewal Expiration

krb.cpp is_ticket_ready_for_renewal() only checks if the ticket renewal expiration is within an hour. I believe the default behavior is the ticket renewal expiration is ~8 days after the actual ticket expiration. This would cause an expired ticket not to be refreshed and possibly provide consumers an expired ticket, since the ticket expired but the refresh expiration has days left. My fork contains a branch that has this fix (The method in my branch is called get_ticket_expiration()). The fix is to actually check the ticket expiration instead. I have not created a PR from this branch since I am waiting for my current active PR to be completed. I updated @smhmhmd about this and will create a PR once the current one is closed.

README issues.

After viewing this blog post from AWS, I came to this repository in order to setup GMSA for Linux containers in AWS ECS. I have had a few problems so far:

  1. The README states that credentials-fetcher can be installed onto Amazon Linux 2022 via sudo yum install credentials-fetcher. This is seems incorrect, given that Amazon Linux 2022 uses dnf, not yum, and also that the package isn't available to dnf. Amazon Linux 2 uses yum, and this package isn't available there either.
  2. There are several places in the code that use the realm command, which is provided by the realmd package. The realmd package is unavailable in Amazon Linux 2022, removed as per this release documentation from AWS. How is this expected to work in Amazon Linux 2022? I'm assuming that this is actually expected to work on Amazon Linux 2.
  3. How is this service expected to be invoked and provide the resulting tickets to a given container? Is the expectation that all containers mount the ticket output directory? If using docker with the credentialspec option, does it invoke this service? How is this usable from an ECS perspective?

Any help or guidance will be greatly appreciated.

Need option to have krb5cc files also written to /var/credentials-fetcher/krbdir/ in format of krb5cc_%{uid}

I'm want to use Credentials-Fetcher in combination with SMB CSI Driver for Kubernetes
https://github.com/kubernetes-csi/csi-driver-smb. Mounting takes place at the worker node level, not inside the pod/container.
That driver currently has no support for pulling updated tickets stored as kubernetes secrets nor refreshing them.
Because of that, I want to use credentials-fetcher to obtain and refresh the kerberos tickets.

To make both work together, I will let the driver go thru its normal process of writing to the hard coded path of
/var/lib/kubelet/kerberos/
but the file it writes into that location (ex: krb5_1000) does not need to be a valid ticket because
/etc/krb5.conf.d/ccache.conf will be configured to point to the credentials-fetcher path of
/var/credentials-fetcher/krbdir/ instead.

As long as credentials-fetcher continues to write into its lease folder structure AND puts a file directly into
/var/credentials-fetcher/krbdir (ex: /var/credentials-fetcher/krbdir/krb5cc_1000), then the mount cifs command will find the valid/refreshed Kerberos ticket and mount.

Note: UID needs to be in the file's name, unlike in the lease subfolders. Ex: krb5_1000, krb5_1001, etc.

Note: I think mechanism could also work for Amazon ECS for mounting CIFS(SMB).

No trace of a unix socket in /var/credentials-fetcher/socket upon compiling for ubuntu 18.04

Problem
I am compiling this code for ubuntu 18.04 in docker. The artifact compiles fine and i can run it but I am not seeing a socket being created under /var/credentials-fetcher/socket. I am probably missing something obvious. Clearly without a socket, any attempt at using grpc_cli or just using the daemon is impossible.

This is what I see when I run the compiled artifact. I should point, in passing, that i tried setting environment variables (e.g. CF_UNIX_DOMAIN_SOCKET_DIR) and that those don't are not getting applied.

# ./credentials-fetcherd
krb_files_dir = /var/credentials-fetcher/krbdir
logging_dir = /var/credentials-fetcher/logging
unix_socket_dir = /var/credentials-fetcher/socket
Thread 0: top of stack near 0x7f23cbdf4e60; argv_string=grpc_thread
Thread 0: top of stack near 0x7f23cb5f3e60; argv_string=krb_ticket_refresh_thread

Replicating
This is the dockerfile that compiles and builds the artifact for ubuntu 18.04

FROM ubuntu:18.04

RUN apt update \
    && apt full-upgrade -y \
    && apt install -y software-properties-common apt-transport-https dnsutils ldap-utils python3-pip wget git vim \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata

# Mono
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF \
    && echo "deb https://download.mono-project.com/repo/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/mono-official-stable.list
# CMake
RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null \
    && echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/kitware.list

RUN apt update \
    && apt install -y libglib2.0-dev libboost-dev libkrb5-dev libsystemd-dev libboost-all-dev libssl-dev \
    && apt install -y cmake mono-complete

RUN cd /root && git clone https://github.com/aws/credentials-fetcher \
    && mkdir -p credentials-fetcher/build \
    && mkdir -p /usr/lib64/glib-2.0/ \
    && ln -s '/usr/lib/x86_64-linux-gnu/glib-2.0/include/' '/usr/lib64/glib-2.0/include' \
    && cd credentials-fetcher/build && cmake ../ && make -j && make install

WORKDIR /root/credentials-fetcher/build
    
CMD ["/bin/bash"]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.