blob: 72429e990329016bf57911ee768ffa6d8cb8531e [file] [log] [blame]
#!/usr/bin/env python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import argparse
import base64
import os
import subprocess
import sys
import tempfile
# we to import Request and urlopen differently for python 2 and 3
try:
from urllib.request import Request
from urllib.request import urlopen
except ImportError:
from urllib2 import Request
from urllib2 import urlopen
DESCRIPTION = """Encrypt a secret for Zuul.
This program fetches a project-specific public key from a Zuul server and
uses that to encrypt a secret. The only pre-requisite is an installed
OpenSSL binary.
"""
def main():
parser = argparse.ArgumentParser(description=DESCRIPTION)
parser.add_argument('url',
help="The base URL of the zuul server and tenant. "
"E.g., https://zuul.example.com/tenant-name")
# TODO(jeblair,mordred): When projects have canonical names, use that here.
# TODO(jeblair): Throw a fit if SSL is not used.
parser.add_argument('source',
help="The Zuul source of the project.")
parser.add_argument('project',
help="The name of the project.")
parser.add_argument('--infile',
default=None,
help="A filename whose contents will be encrypted. "
"If not supplied, the value will be read from "
"standard input.")
parser.add_argument('--outfile',
default=None,
help="A filename to which the encrypted value will be "
"written. If not supplied, the value will be written "
"to standard output.")
args = parser.parse_args()
req = Request("%s/keys/%s/%s.pub" % (
args.url, args.source, args.project))
pubkey = urlopen(req)
if args.infile:
with open(args.infile) as f:
plaintext = f.read()
else:
plaintext = sys.stdin.read()
pubkey_file = tempfile.NamedTemporaryFile(delete=False)
try:
pubkey_file.write(pubkey.read())
pubkey_file.close()
p = subprocess.Popen(['openssl', 'rsautl', '-encrypt',
'-oaep', '-pubin', '-inkey',
pubkey_file.name],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
(stdout, stderr) = p.communicate(plaintext.encode("utf-8"))
if p.returncode != 0:
raise Exception("Return code %s from openssl" % p.returncode)
ciphertext = base64.b64encode(stdout)
finally:
os.unlink(pubkey_file.name)
if args.outfile:
with open(args.outfile, "wb") as f:
f.write(ciphertext)
else:
print(ciphertext.decode("utf-8"))
if __name__ == '__main__':
main()