Synchronizing GnuPG private keys between multiple servers for horizontal scaling - centos7

I am using CentOS 7 and GnuPG 2.0 for one of my applications which is using encryption and decryption.
Now I am trying to scale my application horizontally, on two server named as server A and server B.
Let's say the application creates a private/public key pair on server A, how can I share the same set in server B or vice versa, so that application can access same set of keys from either servers?

Given you do not describe any method which does not store the locally, you're probably using a normal GnuPG home directory with the private key stored in the keychain. Just export this key (gpg --export-secret-keys <key-id>) and then import it (gpg --import) using the same mechanics for distributing other credentials (database, ...).
GnuPG keys do not change "on their own", usually are long-lasting and creation is often a manual process; so you don't need to actively monitor and synchronize them. Just roll out the new copy in the rare case they actually change. Again -- compare the process to database passwords or other secrets.
If keys are actually regenerated regularly, you will have to run the export-import-process whenever creating new keys (and be sure to consider timing issues with the synchronization process not being finished yet, but access is already spread among the servers).
A (much more complex and error-prone, if you don't know the technology in detail) alternative is to use a gpg-agent socket shared over the network, for example by using SSH tunnels or similar solutions. This allows all connected servers to use the private key, without having it stored locally. This might especially prove important if you cannot (may not) store the private key locally. Using gpg-agent socket sharing, the private key is never leaving the server running gpg-agent, which performs all private key operation (the major parts for handling encryption is usually formed by the symmetric encryption of the actual data, but make sure you don't run into scaling issues!).

Related

Safe ways to retain an encryption key in a local service memory after a reboot?

I'm writing a Windows service that receives an encryption key from our web server. Such key never leaves memory and is used to encrypt and decrypt sensitive data. This works well, except for the situation when the system is rebooted. In that case, the network is not yet available (it needs to be authenticated first) thus my service cannot connect to the server yet, but it still needs to obtain the encryption key.
Thus I was wondering if there is a way to safely retain the encryption key in memory after the system is rebooted (without saving it to disk in plaintext, which will expose it)?
How about using NCryptRegisterProtectionDescriptorName / NCryptCreateProtectionDescriptor along with NCryptProtectSecret/NCryptUnprotectSecret?
This is very similar to Remy Lebeau 's suggestion, only using already-existing windows API services. It won't be "in memory" (as memory is lost between boots) but does provide a should-be-secure means of storing such data.

Why does GPGME / GnuPG use pinentry for password input?

GPGME uses a passphrase_cb method to fetch the password from the user for operations, which require access to private keys. This callback can only be overwritten for symmetric encryption, in all other cases the default pinentry is used.
All this effort seems to be pretty uncomfortable, especially because GPGME is an API which shall be used for programming C/C++/... applications. It might be easier (for a programmer who would like to use GPGME) in some cases if the passphrase could be passed to encrypt/sign functions directly. I also saw that other implementations of OpenPGP (to be more precise NetPGP) use a callback.
So I wonder if there is any security specific reason to do so?
GnuPG starting with 2.1 removed the most critical private key functionality into the gpg-agent, to reduce the attack surface on the most intimate secrets -- the private keys.
Such a callback would not only expose the passphrase to the application you're writing (which probably means an even larger attack surface than GnuPG would be), but also GnuPG gets aware of the passphrase.
If you really need to control entry of the passphrase from your application, you have several choices.
Implementing Pinentry
The information flow would then be: your application calls GnuPG through GPGME, GnuPG requests some private key operation from gpg-agent, which again asks your application for the passphrase. Be aware this will only work if you also started the gpg-agent with appropriate pinentry configuration (you might have to start another instance, separate from the one already running on your system).
gpg-preset-passphrase
The most important use case of passing the passphrase directly is in headless daemons, where no humans waits for entering the passphrase. GnuPG also brings a small utility gpg-preset-passphrase (on Debian and derivatives, it is installed as /usr/lib/gnupg2/gpg-preset-passphrase), which also can be used to precache the passphrase (so it is not queried for a configurable time).
Pinentry Loopback
With GnuPG 2.1, another option was added: in gpg-agent, you can allow pinentry loopback with the allow-loopback-pinentry option. An additional parameter pinentry-mode set to loopback in GnuPG/GPGME should allow you to handle passphrase interaction using passphrase_cb again.
But: consider this exposes the passphrase not both your application and GnuPG, and might prove to be a (possibly minor but existing and maybe unnecessary) security risk. Also, GnuPG 2.1 is not yet widely spread, which might be a problem if you do not control the environment.

SAS stored process server vs workspace server

SAS has a stored process server that runs stored processes and a workspace server that runs SAS code. But a stored process is nothing but a combination of SAS code statements, so why can't the workspace server run SAS code?
I am trying to understand why SAS developers came up with the concept of a separate server just for stored processes.
A stored process server reuses the SAS process between runs. It is a stateless server meant to run small pre-written programs and return results. The server maintains a pool of processes and allocates requests to that pool. This minimizes the time to run a job as there is no startup/shut down of the process overhead.
A workspace server is a SAS process that is started for 1 user. Every user connection gets a new SAS process on the server. This server is meant to run more interactive processes where a user runs something, looks at output and then runs something else. Code does not have to be prewritten and stored on the server. In that scenario, startup time is not a limiting factor.
Also, a workspace server can provide additional access to the server. A programmer can use this server to access SAS data sets (via ADO in .NET or JDBC in Java) as well as files on the server.
So there are 2 use cases and these servers address them.
From a developers perspective, the two biggest differences are:
Identity. The stored process server runs under the system account (&sysuserid) configured in the SAS General Servers group, sassrv by default. This will affect permissions (eg database access) at the OS level. Workspace sessions are always run under the client account (logged in user) credentials.
Sessions. The option to retain 'state' by leaving your session alive for a set time period (and accessing the same session again using a session id) is available on for the Stored Process server, however - avoid this pattern at all costs! The reason being, that this session will tie up one of your multibridge ports and play havoc with the load balancing. It's also a poor design choice.
Both stored process and workspace servers can be configured to provide pooled sessions (generic sessions kept alive to be re-used, avoiding startup cost for frequent requests).
To further address your points - a Stored Process is a metadata object which points to (or can also contain) raw sas code. A stored process can run on either type (stored process or workspace) of server. The choice of which will depend on your functional needs above, plus performance considerations as per your pooling and load balancing configuration.

Redundancy without central control point?

If it possible to provide a service to multiple clients whereby if the server providing this service goes down, another one takes it's place- without some sort of centralised "control" which detects whether the main server has gone down and to redirect the clients to the new server?
Is it possible to do without having a centralised interface/gateway?
In other words, its a bit like asking can you design a node balancer without having a centralised control to direct clients?
Well, you are not giving much information about the "service" you are asking about, so I'll answer in a generic way.
For the first part of my answer, I'll assume you are talking about a "centralized interface/gateway" involving ip addresses. For this, there's CARP (Common Address Redundancy Protocol), quoted from the wiki:
The Common Address Redundancy Protocol or CARP is a protocol which
allows multiple hosts on the same local network to share a set of IP
addresses. Its primary purpose is to provide failover redundancy,
especially when used with firewalls and routers. In some
configurations CARP can also provide load balancing functionality. It
is a free, non patent-encumbered alternative to Cisco's HSRP. CARP is
mostly implemented in BSD operating systems.
Quoting the netbsd's "Introduction to CARP":
CARP works by allowing a group of hosts on the same network segment to
share an IP address. This group of hosts is referred to as a
"redundancy group". The redundancy group is assigned an IP address
that is shared amongst the group members. Within the group, one host
is designated the "master" and the rest as "backups". The master host
is the one that currently "holds" the shared IP; it responds to any
traffic or ARP requests directed towards it. Each host may belong to
more than one redundancy group at a time.
This might solve your question at the network level, by having the slaves takeover the ip address in order, without a single point of failure.
Now, for the second part of the answer (the application level), with distributed erlang, you can have several nodes (a cluster) that will give you fault tolerance and redundancy (so you would not use ip addresses here, but "distributed erlang" -a cluster of erlang nodes- instead).
You would have lots of nodes lying around with your Distributed Applciation started, and your application resource file would contain a list of nodes (ordered) where the application can be run.
Distributed erlang will control which of the nodes is "the master" and will automagically start and stop your application in the different nodes, as they go up and down.
Quoting (as less as possible) from http://www.erlang.org/doc/design_principles/distributed_applications.html:
In a distributed system with several Erlang nodes, there may be a need
to control applications in a distributed manner. If the node, where a
certain application is running, goes down, the application should be
restarted at another node.
The application will be started at the first node, specified by the
distributed configuration parameter, which is up and running. The
application is started as usual.
For distribution of application control to work properly, the nodes
where a distributed application may run must contact each other and
negotiate where to start the application.
When started, the node will wait for all nodes specified by
sync_nodes_mandatory and sync_nodes_optional to come up. When all
nodes have come up, or when all mandatory nodes have come up and the
time specified by sync_nodes_timeout has elapsed, all applications
will be started. If not all mandatory nodes have come up, the node
will terminate.
If the node where the application is running goes down, the
application is restarted (after the specified timeout) at the first
node, specified by the distributed configuration parameter, which is
up and running. This is called a failover
distributed = [{Application, [Timeout,] NodeDesc}]
If a node is started, which has higher priority according to
distributed, than the node where a distributed application is
currently running, the application will be restarted at the new node
and stopped at the old node. This is called a takeover.
Ok, that was meant as a general overview, since it can be a long topic :)
For the specific details, it is highly recommended to read the Distributed OTP Applications chapter for learnyousomeerlang (and of course the previous link: http://www.erlang.org/doc/design_principles/distributed_applications.html)
Also, your "service" might depend on other external systems like databases, so you should consider fault tolerance and redundancy there, too. The whole architecture needs to be fault tolerance and distributed for "the service" to work in this way.
Hope it helps!
This answer is a general overview to high availability for networked applications, not specific to Erlang. I don't know too much about what is available in the OTP framework yet because I am new to the language.
There are a few different problems here:
Client connection must be moved to the backup machine
The session may contain state data
How to detect a crash
Problem 1 - Moving client connection
This may be solved in many different ways and on different layers of the network architecture. The easiest thing is to code it right into the client, so that when a connection is lost it reconnects to another machine.
If you need network transparency you may use some technology to sync TCP states between different machines and then reroute all traffic to the new machine, which may be entirely invisible for the client. This is much harder to do than the first suggestion.
I'm sure there are lots of things to do in-between these two.
Problem 2 - State data
You obviously need to transfer the session state from the crashed machine unto the backup machine. This is really hard to do in a reliable way and you may lose the last few transactions because the crashed machine may not be able to send the last state before the crash. You can use a synchronized call in this way to be really sure about not losing state:
Transaction/message comes from the client into the main machine.
Main machine updates some state.
New state is sent to backup machine.
Backup machine confirms arrival of the new state.
Main machine confirms success to the client.
This may potentially be expensive (or at least not responsive enough) in some scenarios since you depend on the backup machine and the connection to it, including latency, before even confirming anything to the client. To make it perform better you can let the client check with the backup machine upon connection what transactions it received and then resend the lost ones, making it the client's responsibility to queue the work.
Problem 3 - Detecting a crash
This is an interesting problem because a crash is not always well-defined. Did something really crash? Consider a network program that closes the connection between the client and server, but both are still up and connected to the network. Or worse, makes the client disconnect from the server without the server noticing. Here are some questions to think about:
Should the client connect to the backup machine?
What if the main server updates some state and send it to the backup machine while the backup have the real client connected - will there be a data race?
Can both the main and backup machine be up at the same time or do you need to shut down work on one of them and move all sessions?
Do you need some sort of authority on this matter, some protocol to decide which one is master and which one is slave? Who is that authority? How do you decentralise it?
What if your nodes loses their connection between them but both continue to work as expected (called network partitioning)?
See Google's paper "Chubby lock server" (PDF) and "Paxos made live" (PDF) to get an idea.
Briefly,this solution involves using a consensus protocol to elect a master among a group of servers that handles all the requests. If the master fails, the protocol is used again to elect the next master.
Also, see gen_leader for an example in leader election which works with detecting failures and transferring service ownership.

Alternatives to LogonUser for network impersonation (C++)

Are there any alternatives to LogonUser and for impersonating given account in order to access network resources? I'm looking for the method of impersonation which would let me connect to machine in foreign domains (or, workgroup machines for the same matter).
For initial data I have: machine name, username (or domain\username), cleartext password.
I know there's a way to establish connection using WNetAddConnection to a \\machinename\ipc$, then most network functions will run in a context of that account, however win2008 added another twist and some functions still use the account, that thread is running under.
I'm also aware, that there's some way to get an impersonation token using SSPI. Have anyone experimented with those tokens, are they good for accessing shares, SCM, remote registry and stuff? Is is what WNetAddConnection is using?
EDIT: To clarify, the reason I cannot use LogonUser is because I need to impersonate user in a non-trusted domain or workgroup
EDIT2: Another clarification: the item I'm trying to implement is similar to psexec, e.g.:
program should not modify host or active directory configuration (e.g.: create temporary local users, etc). Moreover assumption cannot be made that it is running on DC or not
there can be no assumptions made about which software is pre-installed on the remote host, only condition given is that windows file sharing is enabled on target
Account/password is known to be working on target, but target machine may be in local domain, foreign domain, not in domain at all.
EDIT3: I would really love to hear more about SSPI InitializeSecurityContext / AcquireCredentialsHandle option. Is there anybody who has been working with this API extensively? Is it possible to use the tokens returned with impersonation, so that a thread can access network shares and copy files, etc? Can someone post a working code snippet?
EDIT4: Thanks to Marsh Ray, problem got resolved. If anyone is looking to see the proof-of-concept code, it is here
If you're wanting to "access network resources" outside of your forest, do that with WNetAddConnection2/3 as you mentioned, or use the standard RPC APIs with RPC_ C__ AUTHN__ GSS__ NEGOTIATE and and explicit credentials structure.
Normally, "impersonation" is something that happens on the server side. The server side will be able to impersonate the connection as the account you're connecting as.
But the key is this: impersonation only makes sense for impersonating an account the server can access in his local SAM/domain/forest directory. If the client and server are in different forests, they clearly can't agree on the SID of an account for an impersonation token (except for the case of well-known SIDs like Administrator which serve mainly to confuse this kind of thing), and that seems necessary to check against DACLs etc.
Perhaps what you want is to call LogonUserEx with the LOGON32__ LOGON__ NEW__ CREDENTIALS flag. This should succeed (even in a different forest - it doesn't actually authenticate the credentials you give it) giving you a token with the username/password you specified. You may have to use DuplicateToken to turn this into an impersonation token. Then you can use SetThreadToken to replace the token on your thread.
IMHO this isn't really "impersonation", you're just using the credentials outright, but it allows you to access network resources transparently as the arbitrary username/password you supply.
Edit: Oh yeah, be aware that there is no protection against man-in-the-middle on this type of connection. The client especially cannot strongly authenticate the server (short of heroics like IPSEC), so in theory you can't trust anything the server tells you.
The theory goes that you pass the credentials as a SEC_WINNT_AUTH_IDENTITY structure to the AcquireCredentialsHandle function that creates the handle used in InitializeSecurityContext. I never tried this on foreign domains though and I don't know if it works.
Doing this directly and reliably via the Windows API seems next to impossible, plus Windows does so much work behind the scenes to make network access "just work". Plus the impersonation side of things only works for the single thread that called the APIs.
But... you can run a whole program under a different user... such as when you run a service.
So you could edit the registry in your main program to run various services under different security tokens and use IPC/Sockets to communicate with those processes from your main application. ie. a whole bunch (or restarting and reconfiguring the same process) of helper processes running under the different user(s) which your main app abuses.
I realize this is a hack but it seems viable ;)
You could open a command line, map the drive using the plaintext username and password. Then disconnect the drive:
net use m: \\machinename\share password /user:username
... do stuff ...
net use m: /delete
http://technet.microsoft.com/en-us/library/cc756153(WS.10).aspx