為應用建立了rnd的帳號,專門為他們查詢線上數據庫用的,當然,只有他們上了生產網絡以后才能連上數據庫,安全方面我們還是很注意的,呵呵。
授權的語句如下:
grant select on armory.* to rnd;
flush privileges;
select查詢數據沒有問題,但是有的用戶有了更多的需求,他想把數據導出來,簡單的處理的話,可以用select into outfile導出來。自己指定字段的分隔,行分隔等等。
但是用戶一查詢就報:access deny的錯誤,權限不對。
rnd@localhost : armory 09:26:31> select * into outfile ‘/tmp/1.txt’ from os limit 5;
ERROR 1045 (28000): Access denied for user ‘rnd’@'%’ (using password: NO)
郁悶的是MySQL沒有說缺少了那個權限。
在本機測試了一下,
grant all on armory.* to rnd;
flush privileges;
給rnd所有的權限以后,還是報權限錯誤。這個就奇怪了,所有的權限都給它了,還報錯?不可理喻阿。
實在搞不定,最后讓用戶:
mysql -urnd -p -e ‘select * from os limit 5;’ >1.txt
的變通方法。
一直被這個糾結著,突然后來有一天,查詢了一下MySQL的文檔,找到是file的權限沒有加上去,但是當時MySQL對應的庫的所有權限我都加上去了阿。靈光一閃,file是全局的權限,在MySQL中對單個庫是沒有這個權限概念的,所以就算我把庫上的所有權限給了rnd,file的權限其實還是沒有附權給它的。不信的話,我們這就試試:
root@localhost : (none) 09:55:14> grant file on armory.* to rnd;
ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES
果然,File權限是GLOBAL權限,不能附權給數據庫。
GLOBAL FILE附權以后
root@localhost : mysql 09:58:21> grant file on *.* to rnd;
Query OK, 0 rows affected (0.00 sec)
select查詢就可以執行了:
rnd@localhost : armory 10:00:42> select * into outfile ‘/tmp/1.txt’ from os limit 5;
Query OK, 5 rows affected (0.00 sec)
其實MySQL的權限可能比較拗,讓我們一下子適應不過來。MySQL的權限可以精細到列,權限判斷是根據GLOBAL,DB,TABLE,COLUMN來授權的,可以簡單的理解為他們對應到mysql庫中的四個表:user,db,tables_priv,columns_priv這幾個表。當然,MySQL沒有這么簡單拉。有興趣的話可以好好看一下MySQL的reference或者其他介紹。舉個例子:
rnd@localhost : armory 10:00:43> show grants for rnd;
+————————————————-+
| Grants for rnd@% |
+————————————————-+
| GRANT FILE ON *.* TO ‘rnd’@'%’ |
| GRANT ALL PRIVILEGES ON `armory`.* TO ‘rnd’@'%’ |
+————————————————-+
2 rows in set (0.00 sec)
grant對同一個用戶就分了兩行,分別對應著user和db里面的兩行:
root@localhost : mysql 10:18:34> select * from mysql.user where user=’rnd’\G
*************************** 1. row ***************************
Host: %
User: rnd
Password:
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: Y
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
1 row in set (0.00 sec)
root@localhost : mysql 10:18:41> select * from mysql.db where user=’rnd’\G
*************************** 1. row ***************************
Host: %
Db: armory
User: rnd
Select_priv: Y
Insert_priv: Y
Update_priv: Y
Delete_priv: Y
Create_priv: Y
Drop_priv: Y
Grant_priv: N
References_priv: Y
Index_priv: Y
Alter_priv: Y
Create_tmp_table_priv: Y
Lock_tables_priv: Y
Create_view_priv: Y
Show_view_priv: Y
Create_routine_priv: Y
Alter_routine_priv: Y
Execute_priv: Y
Event_priv: Y
Trigger_priv: Y
1 row in set (0.00 sec)
MySQL的權限檢查也是通過檢查這兩個表來進行判斷的。
附上tables_priv和columns_priv的兩個表的字段,和user和db還是有點不同的,用到了set類型。
root@localhost : mysql 10:18:58> desc tables_priv;
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+
| Field | Type | Null | Key | Default | Extra |
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+
| Host | char(60) | NO | PRI | | |
| Db | char(64) | NO | PRI | | |
| User | char(16) | NO | PRI | | |
| Table_name | char(64) | NO | PRI | | |
| Grantor | char(77) | NO | MUL | | |
| Timestamp | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| Table_priv | set(‘Select’,'Insert’,'Update’,'Delete’,'Create’,'Drop’,'Grant’,'References’,'Index’,'Alter’,'Create View’,'Show view’,'Trigger’) | NO | | | |
| Column_priv | set(‘Select’,'Insert’,'Update’,'References’) | NO | | | |
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+
8 rows in set (0.00 sec)
root@localhost : mysql 10:21:24> desc columns_priv;
+————-+———————————————-+——+—–+——————-+—————————–+
| Field | Type | Null | Key | Default | Extra |
+————-+———————————————-+——+—–+——————-+—————————–+
| Host | char(60) | NO | PRI | | |
| Db | char(64) | NO | PRI | | |
| User | char(16) | NO | PRI | | |
| Table_name | char(64) | NO | PRI | | |
| Column_name | char(64) | NO | PRI | | |
| Timestamp | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| Column_priv | set(‘Select’,'Insert’,'Update’,'References’) | NO | | | |
+————-+———————————————-+——+—–+——————-+—————————–+
7 rows in set (0.00 sec)
may your success.
-------------------------------------
我理清是什么問題了。
在red hat系列的linux中selinux對哪些daemon可以進行怎么樣的操作是有限制的,mysql的select into outfile的命令是mysql的daemon來負責寫文件操作的。寫文件之前當然要具有寫文件的權限。而selinux對這個權限做了限制。如果selinux是關閉的吧,這個命令執行是沒有問題的
mysql> select user from user into outfile '/home/test.txt';
Query OK, 2 rows affected (0.02 sec)
當時selinux開啟時
selinux對mysql的守護進程mysqld進行了限制。
mysql> select user from user into outfile '/home/test.txt';
ERROR 1 (HY000): Can't create/write to file '/home/test.txt' (Errcode: 13)
出現了沒有權限寫的error。
解決方法,可以關閉selinux。
可以在/etc/selinux中找到config
root用戶,
shell>vi /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - SELinux is fully disabled.
SELINUX=enforcing
修改SELINUX=disabled關閉selinux就可以了,這個問題就可以解決了。
不過全部關閉SELINUX有帶來一些安全問題。
當然也可以,單獨給mysql的守護進程權限,
shell>getsebool -a可以查看當前的對系統一系列守護進程的權限情況。
lpd_disable_trans --> off
mail_read_content --> off
mailman_mail_disable_trans --> off
mdadm_disable_trans --> off
mozilla_read_content --> off
mysqld_disable_trans --> off
nagios_disable_trans --> off
named_disable_trans --> off
named_write_master_zones --> off
nfs_export_all_ro --> on
nfs_export_all_rw --> on
nfsd_disable_trans --> off
nmbd_disable_trans --> off
nrpe_disable_trans --> off
shell>setsebool -P mysqld_disable_trans=1
開啟對mysql守護進程的權限,這樣
mysql> select user from user into outfile '/home/test.txt';
寫入到自定義的目錄就沒有問題了。
-P表示 是永久性設置,否則重啟之后又恢復預設值。
getsebool setsebool命令在root用戶下有權限。
除了對selinux的權限,當然首先要保證該目錄擁有讀寫權限。
在ubuntu下 ,可以對AppArmor(/etc/apparmor.d/usr.sbin.mysqld) 修改,類似selinux。
添加/etc/squid/lists/eighties.txt w,類似。
---------------------------------------------
root用戶登錄下:
grant file on *.* to webgametest@10.3.18.158;
改為生成在tmp文件夾下。