How to realize virtual hiera data in puppet, or, how to abstract hiera user definitions from user selection on each machine? - puppet

I am trying to define virtual user & group data in hiera, and then realize it only on the nodes where it's needed, by defining user lists and group lists on a per-host basis. Note: I am using the accounts module from puppet forge, and it utilizes the accounts:: name space in hiera. For example, just as a baseline for something that works, if I create this:
# snippet from hiera.yaml
hierarchy:
- name: "Users and Groups"
glob: "UsersAndGroups/*.yaml"
and
# snippet from data/UsersAndGroups/webadmins.yaml
accounts::user_list:
alice:
uid: '999'
gid: '999'
comment: 'Alice User'
shell: '/bin/bash'
bob:
uid: '998'
gid: '998'
comment: 'Bob User'
shell: '/bin/bash'
It works, but the problem is, alice and bob get created on all machines. I only want them to be created on some. I would like to instead, define this data in hiera as virtual and then use a different data structure to specify which resources should be realized on each machine, for example:
# snippet from data/UsersAndGroups/webadmins.yaml
accounts::user_list:
#alice:
uid: '999'
gid: '999'
comment: 'Alice User'
shell: '/bin/bash'
#bob:
uid: '998'
gid: '998'
comment: 'Bob User'
shell: '/bin/bash'
and then create another data structure (and corresponding puppet class, not shown), like so:
# snippet from data/users_by_host/hosts.yaml
realize_accounts::by_host:
host1.example.dom:
- alice
- bob
host2.example.dom:
- bob
host3.example.dom:
- alice
I've tried every variation I can think of to make this work, but have failed so far. The first problem is the virtual resource declaration. It doesn't like me using the # symbol. I receive the error message: found character '#' that cannot start any token.
Can anyone suggest how to abstract the user definitions from the selection of which users should be created on which machines?

I am trying to define virtual user & group data in hiera, and then
realize it only on the nodes where it's needed, by defining user lists
and group lists on a per-host basis.
Ok, that's not unreasonable.
Note: I am using the accounts
module from puppet forge, and it utilizes the accounts:: name space in
hiera.
You can use the puppetlabs/accounts module, but you cannot use its accounts class to manage users or groups if you want to stick to your plan, because it does not provide for declaring those virtually. That is a function of the Puppet code of the declarations, not (directly) of any data the class consumes.
You can still use the Accounts::User defined type, the module's various custom data types, and its custom functions. These perhaps provide enough of a value-add relative to Puppet's core User resource type to make the module worth it. You're probably looking at the core Group resource type in any case. You would need to declare Accounts::User (or User) and Group resources virtually, and then realize the wanted ones based on your per-host lists.
But there are other alternatives. You clarified in comments that your objective is to centralize master lists of user and group properties, from which you can select subsets on a per-machine basis. You can do all of that directly in Hiera with the help of Hiera's alias() interpolation function.
You would do this with a two- (at least) level hierarchy. The user and group details would go into an hierarchy level shared by all hosts, and perhaps accounts::user_defaults and accounts::group_defaults would go there too, if you use them. The accounts::user_list and accounts::group_list would go in a per-host or an otherwise more specific hierarchy level, interpolating elements from the central list. Example:
common.yaml
user:
alice:
uid: '999'
gid: '999'
comment: 'Alice User'
shell: '/bin/bash'
bob:
uid: '998'
gid: '998'
comment: 'Bob User'
shell: '/bin/bash'
host1.yaml
accounts::user_list:
alice: "%{alias('user.alice')}"
bob: "%{alias('user.bob')}"
host2.yaml
accounts::user_list:
bob: "%{alias('user.bob')}"
host3.yaml
accounts::user_list:
alice: "%{alias('user.alice')}"

Related

what is the best way to build multiple permission group on mongodb?

I started a complex project management application and I have the challenge of building resource permissions management for different types of user profiles.
My challenge is:
User story
John is an user with a common user profile.
John creates a project in the application.
John creates several tasks and adds them to the project.
John adds an user responsible for each task.
Added users must have access to the project and the tasks to which they have been added.
John creates a specific task and adds it as a subtask to one of the project's tasks.
In this subtask John adds an user as responsible, automatically that user must have access to the subtask, the task and the project.
And at any time, John can restrict access to a project resource, such as defining that a specific user can only view tasks
The way I started.
I created a specification pattern for each use case, where I inform the variables and it returns a true or false answer.
However, I have to request for each resource and, in my opinion, this is not performative.
What I mentioned is one of the simplest cases, there are others that are more complex.
canEditTaskOnProject(): boolean {
if (!this.project) {
console.error(
`Project not provided on ${TaskPermission.name}.${this.canEditTaskOnProject.name}`
);
return false;
}
return new ProjectLeader(this.project, this.userId)
.or(new Creator(this.task, this.userId))
.or(new FullAccessTaskPermission(this.project, this.userId))
.or(new TaskResponsible(this.task, this.userId))
.or(
new RestrictTaskPermission(this.project, this.userId).and(
new Creator(this.task, this.userId).or(
new TaskResponsible(this.task, this.userId)
)
)
)
.or(
new ReadAndWriteTaskPermission(this.project, this.userId).and(
new TaskResponsible(this.task, this.userId)
)
)
.isSatisfiedBy(this.userId);
}
I would very much like suggestions from experienced people who have already done something similar. I am a beginner in the area and in the company where I work, there are no seniors.
Thank you in advance!
I found the best way using casl:
import { defineAbility } from '#casl/ability';
export default defineAbility((can, cannot) => {
can('read', 'Article');
cannot('read', 'Article', { published: false }); // inverted rule
});

Puppet - How to write yaml files based on Role/Profile method

I've added our infrastructure setup to puppet, and used roles and profiles method. Each profile resides inside a group, based on their nature. For example, Chronyd setup and Message of the day are in "base" group, nginx-related configuration is in "app" group. Also, on the roles, each profile is added to the corresponding group. For example for memcached we have the following:
class role::prod::memcache inherits role::base::debian {
include profile::app::memcache
}
The profile::app::memcached has been set up like this :
class profile::app::memcache {
service { 'memcached':
ensure => running,
enable => true,
hasrestart => true,
hasstatus => true,
}
}
and for role::base::debian I have :
class role::base::debian {
include profile::base::motd
include profile::base::chrony
}
The above structure has proved to be flexible enough for our infrastructure. Adding services and creating new roles could not been easier than this. But now I face a new problem. I've been trying to separate data from logic, write some yaml files to keep the data there, using Hiera version 5. Been looking through internet for a couple of days, but I cannot deduct how to write my hiera files based on the structure I have. I tried adding profile::base::motd to common.yaml and did a puppet lookup, it works fine, but I could not append chrony to common.yaml. Puppet lookup returns nothing with the following common.yaml contents :
---
profile::base::motd::content: This server access is restricted to authorized users only. All activities on this system are logged. Unauthorized access will be liable to prosecution.'
profile::base::chrony::servers: 'ntp.centos.org'
profile::base::chrony::service_enable: 'true'
profile::base::chrony::service_ensure: 'running'
Motd lookup works fine. But the rest, no luck. puppet lookup profile::base::chrony::servers returns with no output. Don't know what I'm missing here. Would really appreciate the community's help on this one.
Also, using hiera, is the following enough code for a service puppet file?
class profile::base::motd {
class { 'motd':
}
}
PS : I know I can add yaml files inside modules to keep the data, but I want my .yaml files to reside in one place (e.g. $PUPPET_HOME/environment/production/data) so I can manage the code with git.
The issue was that in init.pp file inside the puppet module itself, the variable $content was assigned a value. Removing the value fixed the problem.

Retrieve superior hash-key name in Hiera

Hallo I am building in Hiera / Puppet a data structure for creating mysql / config files. My goal ist to have some default values which can be overwritten with a merge. It works until this point.
Because we have different mysql instances on many hosts I want to automaticly configure some paths to be unique for every instance. I have the instance name as a hash (name) of hashes in the Namespace: our_mysql::configure_db::dbs:
In my case I want to lookup the instance names like "sales_db' or 'hr_db' in paths like datadir, but I can not find a way to lookup the superior keyname.
Hiera data from "our_mysql" module represents some default values:
our_mysql::configure_db::dbs:
'defaults':
datadir: /var/lib/mysql/"%{lookup('lookup to superior hash-key name')}"
log_error: /var/log/mysql/"%{lookup('lookup to superior hash-key name')}".log
logbindir: /var/lib/mysql/"%{lookup('lookup to superior hash-key name')}"
db_port: 3306
...: ...
KEY_N: VALUE_N
Hiera data from node definiton:
our_mysql::configure_db::dbs:
'sales_db':
db_port: "3317"
innodb_buffer_pool_size: "1"
innodb_log_file_size: 1GB
innodb_log_files_in_group: "2"
server_id: "1"
'hr_db':
db_port: "3307"
I now how to do simple lookups or to iterate by
.each | String $key, Hash $value | { ... }
but I have no clue how to reference a key from a certain hierarchy level. Searching all related topics to puppet and hiera didn't help.
Is it possible an any way and if yes how?
As I understand the question, I think what you hope to achieve is that, for example, when you look up our_mysql::configure_db::dbs.sales_db key, you get a merge of the data for that (sub)key and those for the our_mysql::configure_db::dbs.defaults subkey, AND that the various %{lookup ...} tokens in the latter somehow resolve to the string sales_db.
I'm afraid that's not going to happen. The interpolation tokens don't even factor in here -- Hiera simply won't perform such a merge at all. I guess you have a hash-merge lookup in mind, but that merges only identical keys and subkeys, so not our_mysql::configure_db::dbs.sales_db and our_mysql::configure_db::dbs.defaults. Hiera provides for defaults for particular keys in the form of data recorded for those specific keys at a low-priority level of the data hierarchy. The "defaults" subkey you present, on the other hand, has no special meaning to the standard Hiera data providers.
You can still address this problem, just not entirely within the data. For example, consider this:
$dbs = lookup('our_mysql::configure_db::dbs', Hash, 'deep')
$dbs.filter |$dbname, $dbparms| { $dbname != 'defaults' }.each |$dbname, $dbparms| {
# Declare a database using a suitable resource type. "my_mysql::database" is
# a dummy resource name for the purposes of this example only
my_mysql::database {
$dbname:
* => $dbparams;
default:
datadir => "/var/lib/mysql/${dbname}",
log_error => "/var/log/mysql/${dbname}.log",
logbindir => "/var/lib/mysql/${dbname}",
* => $dbs['defaults'];
}
}
That supposes data of the form presented in the question, and it uses the data from the defaults subkey where those do not require knowledge of the specific DB name, but it puts the patterns for various directory names into the resource declaration, instead of into the data. The most important things to recognize are the use of the splat * parameter wildcard for obtaining multiple parameters from a hash, and the use per-expression resource property defaults by use of the default keyword in a resource declaration.
If you wanted to do so, you could push more details of the directory names back into the data with a little more effort (and one or more new keys).

DB2 how to get user privilege information when privilege is granted to its group

I grant schema CREATEIN privilege for schema 'test' to user group 'test-group', then add a user 'test-user' into this 'test-group' in Windows OS.
I would like to know what DB2 function or SQL statement can be used to retrieve privilege information for user 'test-user'. I am aware of that the user-group relationship is not defined in DB2, but there must be some ways to look up such relationship data.
As an example, I can create a table successfully in schema 'test' after log in database by user 'test-user' which means the DB2 engine can get 'test-user' CREATEIN privilege inherited from 'test-group'.
I tried to check syscat.schemaauth view by SQL statment
select * from syscat.schemaauth but cannot find user 'test-user' privilege definition only group 'test-group' privilege definition:
GRANTOR GRANTORTYPE GRANTEE GRANTEETYPE SCHEMANAME ALTERINAUTH CREATEAUTH DROPINAUTH
... ....
SYSIBM S PUBLIC G ADMINISTRATOR N Y N
ADMINISTRATOR U TEST G TEST N Y Y
.. ...
You could use the table function AUTH_LIST_GROUPS_FOR_AUTHID to look up the groups for "test-user". That would list ALL groups the user belongs to, including OS groups not used for the database.
SELECT * FROM TABLE (SYSPROC.AUTH_LIST_GROUPS_FOR_AUTHID('TEST-USER')) AS T
There is another view, SYSIBMADM.AUTHORIZATIONIDS, which lists all authorization IDs, i.e., groups, users and roles:
SELECT * FROM SYSIBMADM.AUTHORIZATIONIDS
The last view you need is SYSIBMADM.PRIVILEGES which lists the privileges. Depending on what you need you would combine the three views/table functions
look up the user's groups for groups known to the database
list the privileges for the user AND
list the privileges for all the groups the user belongs to
UPDATE:
I got interested and quickly typed up and tested a query. This should answer it directly. The "or a.authid='PUBLIC'" is needed to include those privileges coming from PUBLIC.
SELECT distinct p.AUTHID, p.PRIVILEGE, p.OBJECTNAME, p.OBJECTSCHEMA, p.OBJECTTYPE
FROM SYSIBMADM.PRIVILEGES P, SYSIBMADM.AUTHORIZATIONIDS A,
TABLE (SYSPROC.AUTH_LIST_GROUPS_FOR_AUTHID('userID')) as U
WHERE p.privilege='CREATEIN' and a.authidtype='G' and a.authid=p.authid
AND (u.group=a.authid or a.authid='PUBLIC')

How do I import members of one GitLab group into another

Does somebody know how I can import all members of one group into another in GitLab, rather than doing it manually one by one?
The only native feature which comes close is in lib/tasks/gitlab/bulk_add_permission.rake, which is mentioned in "User management"
# omnibus-gitlab
sudo gitlab-rake gitlab:import:all_users_to_all_groups
# installation from source
bundle exec rake gitlab:import:all_users_to_all_groups RAILS_ENV=production
You could take that as a model to develop our own task.
I am not aware of such a feature. But you can script it with the API. We use it here to add all users to one single group (all users to all groups is not feasible for our case).
Helpful documentation: http://doc.gitlab.com/ce/api/README.html, http://doc.gitlab.com/ce/api/users.html and http://doc.gitlab.com/ce/api/groups.html
There is also a respond to another question that might be helpful and lists also various modules for various programming languages: Is there a way to add users automatically into gitlab?
I was looking for a solution to Assign all Gitlab users to one particular group.
Here's the solution:
Create this file:
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/finder_import.rake
With this content:
namespace :gitlab do namespace :finder do
desc "GitLab | Add all users to group Colaboradores (admin users are added as owners)"
task importall: :environment do |t, args|
user_ids = User.where(admin: false).pluck(:id)
admin_ids = User.where(admin: true).pluck(:id)
groups = Group.where(name: "Colaboradores")
puts "Importing #{user_ids.size} users into #{groups.size} groups"
puts "Importing #{admin_ids.size} admins into #{groups.size} groups"
groups.each do |group|
puts "Importing into #{group.name}"
group.add_users(user_ids, GroupMember::DEVELOPER)
group.add_users(admin_ids, GroupMember::OWNER)
end
end
end end
Run this command:
gitlab-rake gitlab:finder:importall

Resources