How to allow users to execute a script without revealing protected information

1

Given that the root user has some credentials (say, an API key) set in an environment variable, and given an unprivileged user John, how can I let John execute a script that uses said API key without the risk of leaking its value to John?

WTK

Posted 2018-04-11T08:47:11.327

Reputation: 111

4It feels to me that you would have to have some kind of proxy program running under the root user that does the work for John and passes back the information John wants. – Mokubai – 2018-04-11T09:00:53.867

Hmm, @Mokubai any further pointers or examples I can rely on? And on another note - I've read that with some mumbo-jumbo I can make script executable but not readable, would that work in this case? – WTK – 2018-04-11T12:07:49.657

I don't really see any way that you can make a script executable but not readable somehow. You can run the script as another user, but then you either need to give the user the password or sudo permission to run it which I find hard to believe can be made completely secure to prevent simple reading. If you have evidence to the contrary then that would be good to show. I don't have any examples to hand of how it should be done, there are too many ways and we have no idea what constraints you have except not leaking this key. – Mokubai – 2018-04-11T15:43:35.633

Answers

1

The question seems to be a little unfocused.

  • The question, per se, talks about getting a value from a “super user environment variable” (i.e., a “root environment variable”).  I’m not even sure what that means.  Are you saying that John should get the value from the environment of a(nother) user who is logged in as “root”, or who is running as “root” through su or sudo?  Or are you talking about the environment of a process (probably a background process) running as “root”?

    But, whatever details you have in mind, this sounds like the key is very dynamic and ephemeral.  Since I don’t understand what this means, I won’t say that it’s impossible, but it sounds difficult.

  • But then in a comment you talk about making a script executable but not readable.  This suggests that you’re willing to have the key hard-coded into the script, as long as non-root users can’t read it.  This suggests that the key is very static, changing so rarely that you’re willing to modify the script every time the key changes.

    U&L has a long thread on this very topic: Can a script be executable but not readable?  Sadly, most of the answers are in the negative, or are deflections, diversions, or workarounds, some of which work better than others.  For example, Santana suggests creating an entry in /etc/sudoers that allows John to run the script with elevated permissions, while not being able to read it as himself.  But, if the script doesn’t need elevated permissions (other than for obtaining the key), you don’t want to run it with elevated permissions.

    However, on this related question (on Super User), I present a kludgy way to make a script executable but not readable by wrapping it in a C program.  As I explain in that answer, this technique is not foolproof; there are ways that information can leak out.

  • The most reasonable / plausible interpretation, IMHO, is that the key is kept in a file that John can’t read.  The traditional way of implementing such arrangements is setUID and/or setGID.  (sudo is also useful.)

Here’s an example of how to do that.  Write a C program like this:

#include <stdio.h>
#include <stdlib.h>

#define KEY_FILE        (appropriate pathname)
#define SCRIPT          (appropriate pathname)

main()
{
        FILE    *key_fp;
        char    key[80];        (adjust as appropriate)
        gid_t   gid;
        uid_t   uid;
        char    *args[10];      (adjust as appropriate)

        key_fp = fopen(KEY_FILE, "r");
        if (key_fp == NULL)
        {
                perror(KEY_FILE);
                exit(1);
        }
        (your code to read and validate key)
        fclose(key_fp);
        if (setenv("KEY", key, 1) != 0)
        {
                fprintf(stderr, "Problem with setenv().\n");
                exit(1);
        }
        gid = getgid();
        uid = getuid();
        // use
        //      if (setresgid(gid, gid, gid) != 0  ||  setresuid(uid, uid, uid) != 0)
        // if they’re available; otherwise
        if (setregid(gid, gid) != 0  ||  setreuid(uid, uid) != 0)
        {
                fprintf(stderr, "Problem dropping privileges.\n");
                exit(1);
        }
        args[0] = "scriptname";     (adjust as appropriate)
        args[1] = NULL;
        execv(SCRIPT, args);
        perror(SCRIPT);
        exit(1);
}

Define KEY_FILE to the full pathname to the file that contains the key, and define SCRIPT to the full pathname to the file that contains the script.  Ensure that John has read access to the script, but not the key file, and that he doesn’t have write access to any of the directories in either path.  Arrange for this program to be able to read the key file by making it setUID and/or setGID.  It will read the key, insert it into the environment, drop privileges, and execute the script.  (You may want to modify the above code so that command-line arguments given to the program get passed along to the script.)

As stated above, the script will be run with John’s UID and GID, but with the key in the environment.  On some systems, it may be possible for John to read the script’s environment from /proc/(pid_of_script)/environ or with ps.  If so, it might be helpful to have the script immediately copy the key to a local (non-exported) variable and unset the KEY variable.

It will probably be safe for the script to pass the key to a program

  • through a pipe (e.g., printf "%s" (key_value) | (program)),
  • through a here document, or
  • through a here string.

The risks of passing the value through the environment are mentioned above.  Avoid passing it as a command-line parameter, as this can definitely be seen by ps.

If you want to make the program runnable through sudo, you may need to hard-code John’s UID and GID, because sudo sets the real IDs as well as the effective ones.

G-Man Says 'Reinstate Monica'

Posted 2018-04-11T08:47:11.327

Reputation: 6 509