diff --git a/.gitignore b/.gitignore index 1d88998b07789393e8c45720171bfa9af3cc9eea..7e8eeb4c4f4a996adf3dc219f83c31bbd334d19b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ config.json inventory hosts public_hosts +secrets.auto.tfvars site.pp site2.pp terraform diff --git a/deploy.tf b/deploy.tf index 4cf61ab0fc71175290811d74e242189c2210ad1f..946b044afe17d7518b5ddce5fd612badf56c2499 100644 --- a/deploy.tf +++ b/deploy.tf @@ -53,6 +53,11 @@ EOF } } +variable "secrets" { + type = map(string) + # sensitive = true # terraform >= 0.14 +} + output "config" { value = { n = var.n, @@ -61,6 +66,7 @@ output "config" { master_hostname = var.master_hostname, node_hostname = var.node_hostname, type = var.type, + secrets = var.secrets, } } diff --git a/deployments/hadoop/ctx.yaml b/deployments/hadoop/ctx.yaml index f9478250d49c922068f8834f24d6e640615bc756..600ab5438c237f35bc5318fedf6224bb2a30da4a 100644 --- a/deployments/hadoop/ctx.yaml +++ b/deployments/hadoop/ctx.yaml @@ -20,6 +20,8 @@ write_files: #!/usr/bin/env ruby #^syntax detection forge "https://forgeapi.puppetlabs.com" + mod 'cesnet-kerberos', + :git => 'https://github.com/MetaCenterCloudPuppet/cesnet-kerberos/' mod 'cesnet-site_hadoop', :git => 'https://github.com/MetaCenterCloudPuppet/cesnet-site_hadoop/' mod 'cesnet-hadoop', diff --git a/deployments/hadoop/plugin.py b/deployments/hadoop/plugin.py index b86c171b755bbcd20e901b2c62af16f73c88181a..3a538923f67cb15e5ab3740f455cd36c2442cbd5 100644 --- a/deployments/hadoop/plugin.py +++ b/deployments/hadoop/plugin.py @@ -1,3 +1,4 @@ +import os import string DEFAULT_DISTRIBUTION = 'bigtop' @@ -16,7 +17,9 @@ class ComponentHadoop: 'master_hostname': config['master_hostname'], 'node_hostname': config['node_hostname'], 'nodes': list([h for h in hosts.keys() if h != config['master_hostname']]), - 'realm': '', + 'realm': 'HADOOP', + 'kerberos_admin_password': config['secrets']['kerberos_admin_password'], + 'kerberos_master_password': config['secrets']['kerberos_master_password'], } def action(self, action): @@ -29,11 +32,13 @@ class ComponentHadoop: print('-> site.pp') site = template.substitute(self.params) with open('site.pp', 'w') as f: + os.chmod('site.pp', 0o600) f.write(site) self.params['hdfs_deployed'] = 'true' site = template.substitute(self.params) print('-> site2.pp') with open('site2.pp', 'w') as f: + os.chmod('site2.pp', 0o600) f.write(site) def commands(self, action): diff --git a/deployments/hadoop/site.pp.tmpl b/deployments/hadoop/site.pp.tmpl index cedeff9a6dcec39b3df1ed4e9674e7d3dea6d91c..f739d8833dd1ff22c64be5f192822043999bf71b 100644 --- a/deployments/hadoop/site.pp.tmpl +++ b/deployments/hadoop/site.pp.tmpl @@ -34,6 +34,40 @@ $$db_type = "$${operatingsystem}-$${operatingsystemmajrelease}" ? { default => 'mariadb', } +$$principals = suffix(concat( + prefix(concat([$$master], $$nodes), 'host/'), + prefix(concat([$$master], $$nodes), 'HTTP/'), + ["httpfs/$$master"], + prefix(concat([$$master], $$nodes), 'hbase/'), + ["hive/$$master"], + prefix($$nodes, 'dn/'), + ["jhs/$$master"], + ["nfs/$$master"], + prefix($$nodes, 'nm/'), + ["nn/$$master"], + ["oozie/$$master"], + ["rm/$$master"], + ["spark/$$master"], + ["zookeeper/$$master"] +), "@$${realm}") + +stage { 'kerberos': + before => Stage['main'], +} + +class{"kerberos": + kadmin_hostname => $$master, + admin_principal => "puppet/admin@$${realm}", + admin_password => '$kerberos_admin_password', + master_password => '$kerberos_master_password', + realm => $$realm, + default_attributes => { + 'requires_preauth' => true, + }, + default_policy => 'default_host', + stage => 'kerberos', +} + class{'hadoop': acl => true, hdfs_hostname => $$master, @@ -63,7 +97,8 @@ class{'hadoop': }, properties => { 'dfs.replication' => 2, - 'hadoop.proxyuser.hive.groups' => "*", + 'hadoop.proxyuser.hive.groups' => "hive,impala,oozie,users", + #'hadoop.proxyuser.hive.groups' => "*", 'hadoop.proxyuser.hive.hosts' => "*", }, version => $$hadoop_version, @@ -133,6 +168,9 @@ class{'site_hadoop': 'example', 'hawking', ], + user_realms => [ + '$$realm', + ], accounting_enable => false, hbase_enable => true, nfs_frontend_enable => false, @@ -142,12 +180,126 @@ class{'site_hadoop': } # site_hadoop::users hasn't shell on the nodes, we need exception for '${image_user}' +$$touchfile = 'hdfs-user-${image_user}-created' hadoop::user{'${image_user}': shell => true, hdfs => $$hadoop::hdfs_hostname == $$::fqdn, groups => 'users', realms => $$site_hadoop::user_realms, - touchfile => 'hdfs-user-${image_user}-created', + touchfile => $$touchfile, +} +if $$hadoop::hdfs_hostname == $$::fqdn { + hadoop::kinit{$$touchfile: + } + -> + Hadoop::User <| touchfile == $$touchfile |> + -> + hadoop::kdestroy{$$touchfile: + touch => true, + } +} + +class local_kerberos { + file{'/etc/security/keytab': + ensure => 'directory', + owner => 'root', + group => 'root', + mode => '0755', + } + + File['/etc/security/keytab'] -> Kerberos::Keytab <| |> +} + +class local_kerberos_master { + include local_kerberos + + kerberos::policy{'default': + ensure => 'present', + minlength => 6, + history => 2, + } + + kerberos::policy{'default_host': + ensure => 'present', + minlength => 6, + } + + kerberos::principal{$$::kerberos::admin_principal: + ensure => 'present', + password => $$::kerberos::admin_password, + } + + kerberos::principal{$$principals:} + + kerberos::keytab{'/etc/krb5.keytab': + principals => ["host/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/hive.service.keytab': + principals => ["hive/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/hbase.service.keytab': + principals => ["hbase/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/http.service.keytab': + principals => ["HTTP/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/httpfs.service.keytab': + principals => ["httpfs/$${::fqdn}@$${realm}"], + } + # works only locally on Kerberos admin server! + kerberos::keytab{'/etc/security/keytab/httpfs-http.service.keytab': + principals => [ + "httpfs/$${::fqdn}@$${realm}", + "HTTP/$${::fqdn}@$${realm}", + ], + } + kerberos::keytab{'/etc/security/keytab/jhs.service.keytab': + principals => ["jhs/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/nfs.service.keytab': + principals => ["nfs/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/nn.service.keytab': + principals => ["nn/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/oozie.service.keytab': + principals => ["oozie/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/rm.service.keytab': + principals => ["rm/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/spark.service.keytab': + principals => ["spark/$${::fqdn}@$${realm}"], + } + kerberos::keytab{'/etc/security/keytab/zookeeper.service.keytab': + principals => ["zookeeper/$${::fqdn}@$${realm}"], + } +} + +class local_kerberos_node { + include local_kerberos + + # this will use kerberos::admin_principal and kerberos::admin_password parameters + kerberos::keytab{'/etc/krb5.keytab': + principals => ["host/$${::fqdn}@$${realm}"], + wait => 600, + } + kerberos::keytab{'/etc/security/keytab/dn.service.keytab': + principals => ["dn/$${::fqdn}@$${realm}"], + wait => 600, + } + kerberos::keytab{'/etc/security/keytab/hbase.service.keytab': + principals => ["hbase/$${::fqdn}@$${realm}"], + wait => 600, + } + kerberos::keytab{'/etc/security/keytab/http.service.keytab': + principals => ["HTTP/$${::fqdn}@$${realm}"], + wait => 600, + } + kerberos::keytab{'/etc/security/keytab/nm.service.keytab': + principals => ["nm/$${::fqdn}@$${realm}"], + wait => 600, + } } node /${master_hostname}\..*/ { @@ -163,8 +315,16 @@ node /${master_hostname}\..*/ { root_password => 'root', } #include ::oozie::client + + class{'local_kerberos_master': + stage => 'kerberos', + } } node /${node_hostname}\d*\..*/ { include ::site_hadoop::role::slave + + class{'local_kerberos_node': + stage => 'kerberos', + } } diff --git a/image/Puppetfile b/image/Puppetfile index e9ddf2375d11731d8a453f5f4c6c5010c49c6036..2f71a37fee824c096685922491da65a093259dd6 100644 --- a/image/Puppetfile +++ b/image/Puppetfile @@ -3,6 +3,9 @@ forge "https://forgeapi.puppetlabs.com" +mod 'cesnet-kerberos', + :git => 'https://github.com/MetaCenterCloudPuppet/cesnet-kerberos/' + mod 'cesnet-site_hadoop', :git => 'https://github.com/MetaCenterCloudPuppet/cesnet-site_hadoop/' diff --git a/launch.sh b/launch.sh index 71b6b812cdb32476725e2a2ad1105427e2efdcac..7d63f19869dec63310fb59e653e65c7504e41c89 100755 --- a/launch.sh +++ b/launch.sh @@ -1,4 +1,25 @@ #! /bin/sh -xe + +if [ ! -s ./secrets.auto.tfvars ]; then + touch ./secrets.auto.tfvars + chmod 0600 ./secrets.auto.tfvars + { + echo 'secrets = {' + for k in kerberos_master_password kerberos_admin_password http_signature_secret; do + echo " $k = \"`dd if=/dev/random bs=27 count=1 2>/dev/null | base64 -`\"" + done + echo "}" + } >> ./secrets.auto.tfvars +fi + ./terraform apply -auto-approve "$@" + +touch config.json; chmod 0600 config.json ./terraform output -json > config.json -./orchestrate.py + +if [ -z "$NO_DEPLOYMENT" ]; then + ./orchestrate.py +else + ./orchestrate.py files ping init wait + ./orchestrate.py -n deployment +fi diff --git a/orchestrate.py b/orchestrate.py index 06c7d67a123be4f392ae6b9dfa558474dcedd43d..4f83be64e878aa13d6b4c4e02145c27aca1327b4 100755 --- a/orchestrate.py +++ b/orchestrate.py @@ -52,6 +52,7 @@ public_hosts = j['public_hosts']['value'] master_hostname = config['master_hostname'] master_ip = public_hosts[master_hostname] user = config['image_user'] +secrets = config['secrets'] t = config.get('type', None) print('== plugin ==') diff --git a/secrets.auto.tfvars.example b/secrets.auto.tfvars.example new file mode 100644 index 0000000000000000000000000000000000000000..6a513a791edfa5ecb0fa03d268c504da1ee30ddd --- /dev/null +++ b/secrets.auto.tfvars.example @@ -0,0 +1,5 @@ +secrets = { + kerberos_master_password = "SECRET" + kerberos_admin_password = "SECRET" + http_signature_secret = "SECRET" +}